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

1""" 

2Settings and configuration for Django. 

3 

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""" 

8 

9import importlib 

10import os 

11import time 

12import traceback 

13import warnings 

14from pathlib import Path 

15 

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 

21 

22ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" 

23DEFAULT_STORAGE_ALIAS = "default" 

24STATICFILES_STORAGE_ALIAS = "staticfiles" 

25 

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) 

32 

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) 

38 

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) 

43 

44DEFAULT_FILE_STORAGE_DEPRECATED_MSG = ( 

45 "The DEFAULT_FILE_STORAGE setting is deprecated. Use STORAGES instead." 

46) 

47 

48STATICFILES_STORAGE_DEPRECATED_MSG = ( 

49 "The STATICFILES_STORAGE setting is deprecated. Use STORAGES instead." 

50) 

51 

52 

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 """ 

58 

59 def __new__(self, value, setting_name): 

60 return str.__new__(self, value) 

61 

62 def __init__(self, value, setting_name): 

63 self.setting_name = setting_name 

64 

65 

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 """ 

72 

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 ) 

88 

89 self._wrapped = Settings(settings_module) 

90 

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 } 

98 

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) 

105 

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.") 

112 

113 self.__dict__[name] = val 

114 return val 

115 

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) 

126 

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) 

131 

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 

146 

147 @staticmethod 

148 def _add_script_prefix(value): 

149 """ 

150 Add SCRIPT_NAME prefix to relative paths. 

151 

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 

159 

160 return "%s%s" % (get_script_prefix(), value) 

161 

162 @property 

163 def configured(self): 

164 """Return True if the settings have already been configured.""" 

165 return self._wrapped is not empty 

166 

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) 

175 

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") 

182 

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") 

189 

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") 

197 

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") 

205 

206 

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)) 

213 

214 # store the settings module in case someone later cares 

215 self.SETTINGS_MODULE = settings_module 

216 

217 mod = importlib.import_module(self.SETTINGS_MODULE) 

218 

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) 

230 

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) 

239 

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 ) 

247 

248 if self.is_overridden("USE_DEPRECATED_PYTZ"): 

249 warnings.warn(USE_DEPRECATED_PYTZ_DEPRECATED_MSG, RemovedInDjango50Warning) 

250 

251 if self.is_overridden("CSRF_COOKIE_MASKED"): 

252 warnings.warn(CSRF_COOKIE_MASKED_DEPRECATED_MSG, RemovedInDjango50Warning) 

253 

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() 

265 

266 if self.is_overridden("USE_L10N"): 

267 warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning) 

268 

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) 

275 

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) 

282 

283 def is_overridden(self, setting): 

284 return setting in self._explicit_settings 

285 

286 def __repr__(self): 

287 return '<%(cls)s "%(settings_module)s">' % { 

288 "cls": self.__class__.__name__, 

289 "settings_module": self.SETTINGS_MODULE, 

290 } 

291 

292 

293class UserSettingsHolder: 

294 """Holder for user configured settings.""" 

295 

296 # SETTINGS_MODULE doesn't make much sense in the manually configured 

297 # (standalone) case. 

298 SETTINGS_MODULE = None 

299 

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 

307 

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) 

312 

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 ) 

342 

343 def __delattr__(self, name): 

344 self._deleted.add(name) 

345 if hasattr(self, name): 

346 super().__delattr__(name) 

347 

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 ) 

354 

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 

362 

363 def __repr__(self): 

364 return "<%(cls)s>" % { 

365 "cls": self.__class__.__name__, 

366 } 

367 

368 

369settings = LazySettings()