Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/conf/__init__.py: 15%
176 statements
« prev ^ index » next coverage.py v7.0.5, created at 2023-01-17 06:13 +0000
« prev ^ index » next coverage.py v7.0.5, created at 2023-01-17 06:13 +0000
1"""
2Settings and configuration for Django.
4Read values from the module specified by the DJANGO_SETTINGS_MODULE environment
5variable, and then from django.conf.global_settings; see the global_settings.py
6for a list of all possible variables.
7"""
9import importlib
10import os
11import time
12import traceback
13import warnings
14from pathlib import Path
16import django
17from django.conf import global_settings
18from django.core.exceptions import ImproperlyConfigured
19from django.utils.deprecation import RemovedInDjango50Warning, RemovedInDjango51Warning
20from django.utils.functional import LazyObject, empty
22ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
23DEFAULT_STORAGE_ALIAS = "default"
24STATICFILES_STORAGE_ALIAS = "staticfiles"
26# RemovedInDjango50Warning
27USE_DEPRECATED_PYTZ_DEPRECATED_MSG = (
28 "The USE_DEPRECATED_PYTZ setting, and support for pytz timezones is "
29 "deprecated in favor of the stdlib zoneinfo module. Please update your "
30 "code to use zoneinfo and remove the USE_DEPRECATED_PYTZ setting."
31)
33USE_L10N_DEPRECATED_MSG = (
34 "The USE_L10N setting is deprecated. Starting with Django 5.0, localized "
35 "formatting of data will always be enabled. For example Django will "
36 "display numbers and dates using the format of the current locale."
37)
39CSRF_COOKIE_MASKED_DEPRECATED_MSG = (
40 "The CSRF_COOKIE_MASKED transitional setting is deprecated. Support for "
41 "it will be removed in Django 5.0."
42)
44DEFAULT_FILE_STORAGE_DEPRECATED_MSG = (
45 "The DEFAULT_FILE_STORAGE setting is deprecated. Use STORAGES instead."
46)
48STATICFILES_STORAGE_DEPRECATED_MSG = (
49 "The STATICFILES_STORAGE setting is deprecated. Use STORAGES instead."
50)
53class SettingsReference(str):
54 """
55 String subclass which references a current settings value. It's treated as
56 the value in memory but serializes to a settings.NAME attribute reference.
57 """
59 def __new__(self, value, setting_name):
60 return str.__new__(self, value)
62 def __init__(self, value, setting_name):
63 self.setting_name = setting_name
66class LazySettings(LazyObject):
67 """
68 A lazy proxy for either global Django settings or a custom settings object.
69 The user can manually configure settings prior to using them. Otherwise,
70 Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
71 """
73 def _setup(self, name=None):
74 """
75 Load the settings module pointed to by the environment variable. This
76 is used the first time settings are needed, if the user hasn't
77 configured settings manually.
78 """
79 settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
80 if not settings_module:
81 desc = ("setting %s" % name) if name else "settings"
82 raise ImproperlyConfigured(
83 "Requested %s, but settings are not configured. "
84 "You must either define the environment variable %s "
85 "or call settings.configure() before accessing settings."
86 % (desc, ENVIRONMENT_VARIABLE)
87 )
89 self._wrapped = Settings(settings_module)
91 def __repr__(self):
92 # Hardcode the class name as otherwise it yields 'Settings'.
93 if self._wrapped is empty:
94 return "<LazySettings [Unevaluated]>"
95 return '<LazySettings "%(settings_module)s">' % {
96 "settings_module": self._wrapped.SETTINGS_MODULE,
97 }
99 def __getattr__(self, name):
100 """Return the value of a setting and cache it in self.__dict__."""
101 if (_wrapped := self._wrapped) is empty:
102 self._setup(name)
103 _wrapped = self._wrapped
104 val = getattr(_wrapped, name)
106 # Special case some settings which require further modification.
107 # This is done here for performance reasons so the modified value is cached.
108 if name in {"MEDIA_URL", "STATIC_URL"} and val is not None:
109 val = self._add_script_prefix(val)
110 elif name == "SECRET_KEY" and not val:
111 raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
113 self.__dict__[name] = val
114 return val
116 def __setattr__(self, name, value):
117 """
118 Set the value of setting. Clear all cached values if _wrapped changes
119 (@override_settings does this) or clear single values when set.
120 """
121 if name == "_wrapped":
122 self.__dict__.clear()
123 else:
124 self.__dict__.pop(name, None)
125 super().__setattr__(name, value)
127 def __delattr__(self, name):
128 """Delete a setting and clear it from cache if needed."""
129 super().__delattr__(name)
130 self.__dict__.pop(name, None)
132 def configure(self, default_settings=global_settings, **options):
133 """
134 Called to manually configure the settings. The 'default_settings'
135 parameter sets where to retrieve any unspecified values from (its
136 argument must support attribute access (__getattr__)).
137 """
138 if self._wrapped is not empty:
139 raise RuntimeError("Settings already configured.")
140 holder = UserSettingsHolder(default_settings)
141 for name, value in options.items():
142 if not name.isupper():
143 raise TypeError("Setting %r must be uppercase." % name)
144 setattr(holder, name, value)
145 self._wrapped = holder
147 @staticmethod
148 def _add_script_prefix(value):
149 """
150 Add SCRIPT_NAME prefix to relative paths.
152 Useful when the app is being served at a subpath and manually prefixing
153 subpath to STATIC_URL and MEDIA_URL in settings is inconvenient.
154 """
155 # Don't apply prefix to absolute paths and URLs.
156 if value.startswith(("http://", "https://", "/")):
157 return value
158 from django.urls import get_script_prefix
160 return "%s%s" % (get_script_prefix(), value)
162 @property
163 def configured(self):
164 """Return True if the settings have already been configured."""
165 return self._wrapped is not empty
167 def _show_deprecation_warning(self, message, category):
168 stack = traceback.extract_stack()
169 # Show a warning if the setting is used outside of Django.
170 # Stack index: -1 this line, -2 the property, -3 the
171 # LazyObject __getattribute__(), -4 the caller.
172 filename, _, _, _ = stack[-4]
173 if not filename.startswith(os.path.dirname(django.__file__)):
174 warnings.warn(message, category, stacklevel=2)
176 @property
177 def USE_L10N(self):
178 self._show_deprecation_warning(
179 USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning
180 )
181 return self.__getattr__("USE_L10N")
183 # RemovedInDjango50Warning.
184 @property
185 def _USE_L10N_INTERNAL(self):
186 # Special hook to avoid checking a traceback in internal use on hot
187 # paths.
188 return self.__getattr__("USE_L10N")
190 # RemovedInDjango51Warning.
191 @property
192 def DEFAULT_FILE_STORAGE(self):
193 self._show_deprecation_warning(
194 DEFAULT_FILE_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning
195 )
196 return self.__getattr__("DEFAULT_FILE_STORAGE")
198 # RemovedInDjango51Warning.
199 @property
200 def STATICFILES_STORAGE(self):
201 self._show_deprecation_warning(
202 STATICFILES_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning
203 )
204 return self.__getattr__("STATICFILES_STORAGE")
207class Settings:
208 def __init__(self, settings_module):
209 # update this dict from global settings (but only for ALL_CAPS settings)
210 for setting in dir(global_settings):
211 if setting.isupper():
212 setattr(self, setting, getattr(global_settings, setting))
214 # store the settings module in case someone later cares
215 self.SETTINGS_MODULE = settings_module
217 mod = importlib.import_module(self.SETTINGS_MODULE)
219 tuple_settings = (
220 "ALLOWED_HOSTS",
221 "INSTALLED_APPS",
222 "TEMPLATE_DIRS",
223 "LOCALE_PATHS",
224 "SECRET_KEY_FALLBACKS",
225 )
226 self._explicit_settings = set()
227 for setting in dir(mod):
228 if setting.isupper():
229 setting_value = getattr(mod, setting)
231 if setting in tuple_settings and not isinstance(
232 setting_value, (list, tuple)
233 ):
234 raise ImproperlyConfigured(
235 "The %s setting must be a list or a tuple." % setting
236 )
237 setattr(self, setting, setting_value)
238 self._explicit_settings.add(setting)
240 if self.USE_TZ is False and not self.is_overridden("USE_TZ"):
241 warnings.warn(
242 "The default value of USE_TZ will change from False to True "
243 "in Django 5.0. Set USE_TZ to False in your project settings "
244 "if you want to keep the current default behavior.",
245 category=RemovedInDjango50Warning,
246 )
248 if self.is_overridden("USE_DEPRECATED_PYTZ"):
249 warnings.warn(USE_DEPRECATED_PYTZ_DEPRECATED_MSG, RemovedInDjango50Warning)
251 if self.is_overridden("CSRF_COOKIE_MASKED"):
252 warnings.warn(CSRF_COOKIE_MASKED_DEPRECATED_MSG, RemovedInDjango50Warning)
254 if hasattr(time, "tzset") and self.TIME_ZONE:
255 # When we can, attempt to validate the timezone. If we can't find
256 # this file, no check happens and it's harmless.
257 zoneinfo_root = Path("/usr/share/zoneinfo")
258 zone_info_file = zoneinfo_root.joinpath(*self.TIME_ZONE.split("/"))
259 if zoneinfo_root.exists() and not zone_info_file.exists():
260 raise ValueError("Incorrect timezone setting: %s" % self.TIME_ZONE)
261 # Move the time zone info into os.environ. See ticket #2315 for why
262 # we don't do this unconditionally (breaks Windows).
263 os.environ["TZ"] = self.TIME_ZONE
264 time.tzset()
266 if self.is_overridden("USE_L10N"):
267 warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
269 if self.is_overridden("DEFAULT_FILE_STORAGE"):
270 if self.is_overridden("STORAGES"):
271 raise ImproperlyConfigured(
272 "DEFAULT_FILE_STORAGE/STORAGES are mutually exclusive."
273 )
274 warnings.warn(DEFAULT_FILE_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning)
276 if self.is_overridden("STATICFILES_STORAGE"):
277 if self.is_overridden("STORAGES"):
278 raise ImproperlyConfigured(
279 "STATICFILES_STORAGE/STORAGES are mutually exclusive."
280 )
281 warnings.warn(STATICFILES_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning)
283 def is_overridden(self, setting):
284 return setting in self._explicit_settings
286 def __repr__(self):
287 return '<%(cls)s "%(settings_module)s">' % {
288 "cls": self.__class__.__name__,
289 "settings_module": self.SETTINGS_MODULE,
290 }
293class UserSettingsHolder:
294 """Holder for user configured settings."""
296 # SETTINGS_MODULE doesn't make much sense in the manually configured
297 # (standalone) case.
298 SETTINGS_MODULE = None
300 def __init__(self, default_settings):
301 """
302 Requests for configuration variables not in this class are satisfied
303 from the module specified in default_settings (if possible).
304 """
305 self.__dict__["_deleted"] = set()
306 self.default_settings = default_settings
308 def __getattr__(self, name):
309 if not name.isupper() or name in self._deleted:
310 raise AttributeError
311 return getattr(self.default_settings, name)
313 def __setattr__(self, name, value):
314 self._deleted.discard(name)
315 if name == "USE_L10N":
316 warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
317 if name == "CSRF_COOKIE_MASKED":
318 warnings.warn(CSRF_COOKIE_MASKED_DEPRECATED_MSG, RemovedInDjango50Warning)
319 if name == "DEFAULT_FILE_STORAGE":
320 self.STORAGES[DEFAULT_STORAGE_ALIAS] = {
321 "BACKEND": self.DEFAULT_FILE_STORAGE
322 }
323 warnings.warn(DEFAULT_FILE_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning)
324 if name == "STATICFILES_STORAGE":
325 self.STORAGES[STATICFILES_STORAGE_ALIAS] = {
326 "BACKEND": self.STATICFILES_STORAGE
327 }
328 warnings.warn(STATICFILES_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning)
329 super().__setattr__(name, value)
330 if name == "USE_DEPRECATED_PYTZ":
331 warnings.warn(USE_DEPRECATED_PYTZ_DEPRECATED_MSG, RemovedInDjango50Warning)
332 # RemovedInDjango51Warning.
333 if name == "STORAGES":
334 self.STORAGES.setdefault(
335 DEFAULT_STORAGE_ALIAS,
336 {"BACKEND": "django.core.files.storage.FileSystemStorage"},
337 )
338 self.STORAGES.setdefault(
339 STATICFILES_STORAGE_ALIAS,
340 {"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"},
341 )
343 def __delattr__(self, name):
344 self._deleted.add(name)
345 if hasattr(self, name):
346 super().__delattr__(name)
348 def __dir__(self):
349 return sorted(
350 s
351 for s in [*self.__dict__, *dir(self.default_settings)]
352 if s not in self._deleted
353 )
355 def is_overridden(self, setting):
356 deleted = setting in self._deleted
357 set_locally = setting in self.__dict__
358 set_on_default = getattr(
359 self.default_settings, "is_overridden", lambda s: False
360 )(setting)
361 return deleted or set_locally or set_on_default
363 def __repr__(self):
364 return "<%(cls)s>" % {
365 "cls": self.__class__.__name__,
366 }
369settings = LazySettings()