Skip to content

Instantly share code, notes, and snippets.

@gimntut
Created August 31, 2020 06:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gimntut/c1d61029e44461d7510f786557bb92c3 to your computer and use it in GitHub Desktop.
Save gimntut/c1d61029e44461d7510f786557bb92c3 to your computer and use it in GitHub Desktop.
from typing import Any
from django.conf import settings
from django.utils.module_loading import import_string
def import_from_string(val, setting_name):
"""
Attempt to import a class from a string representation.
"""
try:
return import_string(val)
except ImportError as e:
msg = "Could not import '%s' for setting '%s'. %s: %s." % (val, setting_name, e.__class__.__name__, e)
raise ImportError(msg)
def perform_import(val, setting_name):
"""
If the given setting is a string import notation,
then perform the necessary import or imports.
"""
if val is None:
return None
elif isinstance(val, str):
return import_from_string(val, setting_name)
elif isinstance(val, (list, tuple)):
return [import_from_string(item, setting_name) for item in val]
return val
class SimpleAppSettings:
defaults = {}
transforms = {}
import_strings = []
def __init__(self, setting_name, defaults=None, import_strings=None, transforms=None) -> None:
super().__init__()
self.defaults = defaults or self.defaults
self.user_settings = getattr(settings, setting_name, {})
self.import_strings = import_strings or self.import_strings
self.transforms = transforms or self.transforms
self._cached_attrs = set()
def __getattr__(self, attr):
if attr not in self.defaults:
raise AttributeError("Invalid setting: '%s'" % attr)
try:
# Check if present in user settings
val = self.user_settings[attr]
except KeyError:
# Fall back to defaults
val = self.defaults[attr]
if attr in self.transforms:
val = self.transforms[attr](val)
# Coerce import strings into classes
if attr in self.import_strings:
val = perform_import(val, attr)
# Cache the result
self._cached_attrs.add(attr)
setattr(self, attr, val)
return val
def __dir__(self):
return [*self.defaults.keys()]
class AppSettings(SimpleAppSettings):
def __init__(self, setting_name, defaults=None, import_strings=None, transforms=None) -> None:
d = {k: v for k, v in self.__class__.__dict__.items() if not k.startswith('_')}
d.pop('defaults', None)
d.pop('transforms', None)
d.pop('import_strings', None)
d.update(defaults or {})
super().__init__(setting_name, defaults=d, import_strings=import_strings, transforms=transforms)
def __getattribute__(self, name: str) -> Any:
if name != 'defaults' and name in self.defaults:
return self.__getattr__(name)
return object.__getattribute__(self, name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment