Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/conf/__init__.py: 39%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

124 statements  

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.functional import LazyObject, empty 

20 

21ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" 

22DEFAULT_STORAGE_ALIAS = "default" 

23STATICFILES_STORAGE_ALIAS = "staticfiles" 

24 

25 

26class SettingsReference(str): 

27 """ 

28 String subclass which references a current settings value. It's treated as 

29 the value in memory but serializes to a settings.NAME attribute reference. 

30 """ 

31 

32 def __new__(self, value, setting_name): 

33 return str.__new__(self, value) 

34 

35 def __init__(self, value, setting_name): 

36 self.setting_name = setting_name 

37 

38 

39class LazySettings(LazyObject): 

40 """ 

41 A lazy proxy for either global Django settings or a custom settings object. 

42 The user can manually configure settings prior to using them. Otherwise, 

43 Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE. 

44 """ 

45 

46 def _setup(self, name=None): 

47 """ 

48 Load the settings module pointed to by the environment variable. This 

49 is used the first time settings are needed, if the user hasn't 

50 configured settings manually. 

51 """ 

52 settings_module = os.environ.get(ENVIRONMENT_VARIABLE) 

53 if not settings_module: 

54 desc = ("setting %s" % name) if name else "settings" 

55 raise ImproperlyConfigured( 

56 "Requested %s, but settings are not configured. " 

57 "You must either define the environment variable %s " 

58 "or call settings.configure() before accessing settings." 

59 % (desc, ENVIRONMENT_VARIABLE) 

60 ) 

61 

62 self._wrapped = Settings(settings_module) 

63 

64 def __repr__(self): 

65 # Hardcode the class name as otherwise it yields 'Settings'. 

66 if self._wrapped is empty: 

67 return "<LazySettings [Unevaluated]>" 

68 return '<LazySettings "%(settings_module)s">' % { 

69 "settings_module": self._wrapped.SETTINGS_MODULE, 

70 } 

71 

72 def __getattr__(self, name): 

73 """Return the value of a setting and cache it in self.__dict__.""" 

74 if (_wrapped := self._wrapped) is empty: 

75 self._setup(name) 

76 _wrapped = self._wrapped 

77 val = getattr(_wrapped, name) 

78 

79 # Special case some settings which require further modification. 

80 # This is done here for performance reasons so the modified value is cached. 

81 if name in {"MEDIA_URL", "STATIC_URL"} and val is not None: 

82 val = self._add_script_prefix(val) 

83 elif name == "SECRET_KEY" and not val: 

84 raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.") 

85 

86 self.__dict__[name] = val 

87 return val 

88 

89 def __setattr__(self, name, value): 

90 """ 

91 Set the value of setting. Clear all cached values if _wrapped changes 

92 (@override_settings does this) or clear single values when set. 

93 """ 

94 if name == "_wrapped": 

95 self.__dict__.clear() 

96 else: 

97 self.__dict__.pop(name, None) 

98 super().__setattr__(name, value) 

99 

100 def __delattr__(self, name): 

101 """Delete a setting and clear it from cache if needed.""" 

102 super().__delattr__(name) 

103 self.__dict__.pop(name, None) 

104 

105 def configure(self, default_settings=global_settings, **options): 

106 """ 

107 Called to manually configure the settings. The 'default_settings' 

108 parameter sets where to retrieve any unspecified values from (its 

109 argument must support attribute access (__getattr__)). 

110 """ 

111 if self._wrapped is not empty: 

112 raise RuntimeError("Settings already configured.") 

113 holder = UserSettingsHolder(default_settings) 

114 for name, value in options.items(): 

115 if not name.isupper(): 

116 raise TypeError("Setting %r must be uppercase." % name) 

117 setattr(holder, name, value) 

118 self._wrapped = holder 

119 

120 @staticmethod 

121 def _add_script_prefix(value): 

122 """ 

123 Add SCRIPT_NAME prefix to relative paths. 

124 

125 Useful when the app is being served at a subpath and manually prefixing 

126 subpath to STATIC_URL and MEDIA_URL in settings is inconvenient. 

127 """ 

128 # Don't apply prefix to absolute paths and URLs. 

129 if value.startswith(("http://", "https://", "/")): 

130 return value 

131 from django.urls import get_script_prefix 

132 

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

134 

135 @property 

136 def configured(self): 

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

138 return self._wrapped is not empty 

139 

140 def _show_deprecation_warning(self, message, category): 

141 stack = traceback.extract_stack() 

142 # Show a warning if the setting is used outside of Django. 

143 # Stack index: -1 this line, -2 the property, -3 the 

144 # LazyObject __getattribute__(), -4 the caller. 

145 filename, _, _, _ = stack[-4] 

146 if not filename.startswith(os.path.dirname(django.__file__)): 

147 warnings.warn(message, category, stacklevel=2) 

148 

149 

150class Settings: 

151 def __init__(self, settings_module): 

152 # update this dict from global settings (but only for ALL_CAPS settings) 

153 for setting in dir(global_settings): 

154 if setting.isupper(): 

155 setattr(self, setting, getattr(global_settings, setting)) 

156 

157 # store the settings module in case someone later cares 

158 self.SETTINGS_MODULE = settings_module 

159 

160 mod = importlib.import_module(self.SETTINGS_MODULE) 

161 

162 tuple_settings = ( 

163 "ALLOWED_HOSTS", 

164 "INSTALLED_APPS", 

165 "TEMPLATE_DIRS", 

166 "LOCALE_PATHS", 

167 "SECRET_KEY_FALLBACKS", 

168 ) 

169 self._explicit_settings = set() 

170 for setting in dir(mod): 

171 if setting.isupper(): 

172 setting_value = getattr(mod, setting) 

173 

174 if setting in tuple_settings and not isinstance( 

175 setting_value, (list, tuple) 

176 ): 

177 raise ImproperlyConfigured( 

178 "The %s setting must be a list or a tuple." % setting 

179 ) 

180 setattr(self, setting, setting_value) 

181 self._explicit_settings.add(setting) 

182 

183 if hasattr(time, "tzset") and self.TIME_ZONE: 

184 # When we can, attempt to validate the timezone. If we can't find 

185 # this file, no check happens and it's harmless. 

186 zoneinfo_root = Path("/usr/share/zoneinfo") 

187 zone_info_file = zoneinfo_root.joinpath(*self.TIME_ZONE.split("/")) 

188 if zoneinfo_root.exists() and not zone_info_file.exists(): 

189 raise ValueError("Incorrect timezone setting: %s" % self.TIME_ZONE) 

190 # Move the time zone info into os.environ. See ticket #2315 for why 

191 # we don't do this unconditionally (breaks Windows). 

192 os.environ["TZ"] = self.TIME_ZONE 

193 time.tzset() 

194 

195 def is_overridden(self, setting): 

196 return setting in self._explicit_settings 

197 

198 def __repr__(self): 

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

200 "cls": self.__class__.__name__, 

201 "settings_module": self.SETTINGS_MODULE, 

202 } 

203 

204 

205class UserSettingsHolder: 

206 """Holder for user configured settings.""" 

207 

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

209 # (standalone) case. 

210 SETTINGS_MODULE = None 

211 

212 def __init__(self, default_settings): 

213 """ 

214 Requests for configuration variables not in this class are satisfied 

215 from the module specified in default_settings (if possible). 

216 """ 

217 self.__dict__["_deleted"] = set() 

218 self.default_settings = default_settings 

219 

220 def __getattr__(self, name): 

221 if not name.isupper() or name in self._deleted: 

222 raise AttributeError 

223 return getattr(self.default_settings, name) 

224 

225 def __setattr__(self, name, value): 

226 self._deleted.discard(name) 

227 super().__setattr__(name, value) 

228 

229 def __delattr__(self, name): 

230 self._deleted.add(name) 

231 if hasattr(self, name): 

232 super().__delattr__(name) 

233 

234 def __dir__(self): 

235 return sorted( 

236 s 

237 for s in [*self.__dict__, *dir(self.default_settings)] 

238 if s not in self._deleted 

239 ) 

240 

241 def is_overridden(self, setting): 

242 deleted = setting in self._deleted 

243 set_locally = setting in self.__dict__ 

244 set_on_default = getattr( 

245 self.default_settings, "is_overridden", lambda s: False 

246 )(setting) 

247 return deleted or set_locally or set_on_default 

248 

249 def __repr__(self): 

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

251 "cls": self.__class__.__name__, 

252 } 

253 

254 

255settings = LazySettings()