OLD | NEW |
(Empty) | |
| 1 """ |
| 2 Settings and configuration for Django. |
| 3 |
| 4 Values will be read from the module specified by the DJANGO_SETTINGS_MODULE envi
ronment |
| 5 variable, and then from django.conf.global_settings; see the global settings fil
e for |
| 6 a list of all possible variables. |
| 7 """ |
| 8 |
| 9 import importlib |
| 10 import os |
| 11 import time |
| 12 |
| 13 from django.conf import global_settings |
| 14 from django.core.exceptions import ImproperlyConfigured |
| 15 from django.utils.functional import LazyObject, empty |
| 16 |
| 17 ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" |
| 18 |
| 19 |
| 20 class LazySettings(LazyObject): |
| 21 """ |
| 22 A lazy proxy for either global Django settings or a custom settings object. |
| 23 The user can manually configure settings prior to using them. Otherwise, |
| 24 Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE. |
| 25 """ |
| 26 def _setup(self, name=None): |
| 27 """ |
| 28 Load the settings module pointed to by the environment variable. This |
| 29 is used the first time we need any settings at all, if the user has not |
| 30 previously configured the settings manually. |
| 31 """ |
| 32 settings_module = os.environ.get(ENVIRONMENT_VARIABLE) |
| 33 if not settings_module: |
| 34 desc = ("setting %s" % name) if name else "settings" |
| 35 raise ImproperlyConfigured( |
| 36 "Requested %s, but settings are not configured. " |
| 37 "You must either define the environment variable %s " |
| 38 "or call settings.configure() before accessing settings." |
| 39 % (desc, ENVIRONMENT_VARIABLE)) |
| 40 |
| 41 self._wrapped = Settings(settings_module) |
| 42 |
| 43 def __repr__(self): |
| 44 # Hardcode the class name as otherwise it yields 'Settings'. |
| 45 if self._wrapped is empty: |
| 46 return '<LazySettings [Unevaluated]>' |
| 47 return '<LazySettings "%(settings_module)s">' % { |
| 48 'settings_module': self._wrapped.SETTINGS_MODULE, |
| 49 } |
| 50 |
| 51 def __getattr__(self, name): |
| 52 """ |
| 53 Return the value of a setting and cache it in self.__dict__. |
| 54 """ |
| 55 if self._wrapped is empty: |
| 56 self._setup(name) |
| 57 val = getattr(self._wrapped, name) |
| 58 self.__dict__[name] = val |
| 59 return val |
| 60 |
| 61 def __setattr__(self, name, value): |
| 62 """ |
| 63 Set the value of setting. Clear all cached values if _wrapped changes |
| 64 (@override_settings does this) or clear single values when set. |
| 65 """ |
| 66 if name == '_wrapped': |
| 67 self.__dict__.clear() |
| 68 else: |
| 69 self.__dict__.pop(name, None) |
| 70 super(LazySettings, self).__setattr__(name, value) |
| 71 |
| 72 def __delattr__(self, name): |
| 73 """ |
| 74 Delete a setting and clear it from cache if needed. |
| 75 """ |
| 76 super(LazySettings, self).__delattr__(name) |
| 77 self.__dict__.pop(name, None) |
| 78 |
| 79 def configure(self, default_settings=global_settings, **options): |
| 80 """ |
| 81 Called to manually configure the settings. The 'default_settings' |
| 82 parameter sets where to retrieve any unspecified values from (its |
| 83 argument must support attribute access (__getattr__)). |
| 84 """ |
| 85 if self._wrapped is not empty: |
| 86 raise RuntimeError('Settings already configured.') |
| 87 holder = UserSettingsHolder(default_settings) |
| 88 for name, value in options.items(): |
| 89 setattr(holder, name, value) |
| 90 self._wrapped = holder |
| 91 |
| 92 @property |
| 93 def configured(self): |
| 94 """ |
| 95 Returns True if the settings have already been configured. |
| 96 """ |
| 97 return self._wrapped is not empty |
| 98 |
| 99 |
| 100 class Settings(object): |
| 101 def __init__(self, settings_module): |
| 102 # update this dict from global settings (but only for ALL_CAPS settings) |
| 103 for setting in dir(global_settings): |
| 104 if setting.isupper(): |
| 105 setattr(self, setting, getattr(global_settings, setting)) |
| 106 |
| 107 # store the settings module in case someone later cares |
| 108 self.SETTINGS_MODULE = settings_module |
| 109 |
| 110 mod = importlib.import_module(self.SETTINGS_MODULE) |
| 111 |
| 112 tuple_settings = ( |
| 113 "INSTALLED_APPS", |
| 114 "TEMPLATE_DIRS", |
| 115 "LOCALE_PATHS", |
| 116 ) |
| 117 self._explicit_settings = set() |
| 118 for setting in dir(mod): |
| 119 if setting.isupper(): |
| 120 setting_value = getattr(mod, setting) |
| 121 |
| 122 if (setting in tuple_settings and |
| 123 not isinstance(setting_value, (list, tuple))): |
| 124 raise ImproperlyConfigured("The %s setting must be a list or
a tuple. " % setting) |
| 125 setattr(self, setting, setting_value) |
| 126 self._explicit_settings.add(setting) |
| 127 |
| 128 if not self.SECRET_KEY: |
| 129 raise ImproperlyConfigured("The SECRET_KEY setting must not be empty
.") |
| 130 |
| 131 if hasattr(time, 'tzset') and self.TIME_ZONE: |
| 132 # When we can, attempt to validate the timezone. If we can't find |
| 133 # this file, no check happens and it's harmless. |
| 134 zoneinfo_root = '/usr/share/zoneinfo' |
| 135 if (os.path.exists(zoneinfo_root) and not |
| 136 os.path.exists(os.path.join(zoneinfo_root, *(self.TIME_ZONE.
split('/'))))): |
| 137 raise ValueError("Incorrect timezone setting: %s" % self.TIME_ZO
NE) |
| 138 # Move the time zone info into os.environ. See ticket #2315 for why |
| 139 # we don't do this unconditionally (breaks Windows). |
| 140 os.environ['TZ'] = self.TIME_ZONE |
| 141 time.tzset() |
| 142 |
| 143 def is_overridden(self, setting): |
| 144 return setting in self._explicit_settings |
| 145 |
| 146 def __repr__(self): |
| 147 return '<%(cls)s "%(settings_module)s">' % { |
| 148 'cls': self.__class__.__name__, |
| 149 'settings_module': self.SETTINGS_MODULE, |
| 150 } |
| 151 |
| 152 |
| 153 class UserSettingsHolder(object): |
| 154 """ |
| 155 Holder for user configured settings. |
| 156 """ |
| 157 # SETTINGS_MODULE doesn't make much sense in the manually configured |
| 158 # (standalone) case. |
| 159 SETTINGS_MODULE = None |
| 160 |
| 161 def __init__(self, default_settings): |
| 162 """ |
| 163 Requests for configuration variables not in this class are satisfied |
| 164 from the module specified in default_settings (if possible). |
| 165 """ |
| 166 self.__dict__['_deleted'] = set() |
| 167 self.default_settings = default_settings |
| 168 |
| 169 def __getattr__(self, name): |
| 170 if name in self._deleted: |
| 171 raise AttributeError |
| 172 return getattr(self.default_settings, name) |
| 173 |
| 174 def __setattr__(self, name, value): |
| 175 self._deleted.discard(name) |
| 176 super(UserSettingsHolder, self).__setattr__(name, value) |
| 177 |
| 178 def __delattr__(self, name): |
| 179 self._deleted.add(name) |
| 180 if hasattr(self, name): |
| 181 super(UserSettingsHolder, self).__delattr__(name) |
| 182 |
| 183 def __dir__(self): |
| 184 return sorted( |
| 185 s for s in list(self.__dict__) + dir(self.default_settings) |
| 186 if s not in self._deleted |
| 187 ) |
| 188 |
| 189 def is_overridden(self, setting): |
| 190 deleted = (setting in self._deleted) |
| 191 set_locally = (setting in self.__dict__) |
| 192 set_on_default = getattr(self.default_settings, 'is_overridden', lambda
s: False)(setting) |
| 193 return (deleted or set_locally or set_on_default) |
| 194 |
| 195 def __repr__(self): |
| 196 return '<%(cls)s>' % { |
| 197 'cls': self.__class__.__name__, |
| 198 } |
| 199 |
| 200 |
| 201 settings = LazySettings() |
OLD | NEW |