|
1 """ |
|
2 Settings and configuration for Django. |
|
3 |
|
4 Values will be read from the module specified by the DJANGO_SETTINGS_MODULE environment |
|
5 variable, and then from django.conf.global_settings; see the global settings file for |
|
6 a list of all possible variables. |
|
7 """ |
|
8 |
|
9 import os |
|
10 import time # Needed for Windows |
|
11 from django.conf import global_settings |
|
12 |
|
13 ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" |
|
14 |
|
15 class LazySettings(object): |
|
16 """ |
|
17 A lazy proxy for either global Django settings or a custom settings object. |
|
18 The user can manually configure settings prior to using them. Otherwise, |
|
19 Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE. |
|
20 """ |
|
21 def __init__(self): |
|
22 # _target must be either None or something that supports attribute |
|
23 # access (getattr, hasattr, etc). |
|
24 self._target = None |
|
25 |
|
26 def __getattr__(self, name): |
|
27 if self._target is None: |
|
28 self._import_settings() |
|
29 if name == '__members__': |
|
30 # Used to implement dir(obj), for example. |
|
31 return self._target.get_all_members() |
|
32 return getattr(self._target, name) |
|
33 |
|
34 def __setattr__(self, name, value): |
|
35 if name == '_target': |
|
36 # Assign directly to self.__dict__, because otherwise we'd call |
|
37 # __setattr__(), which would be an infinite loop. |
|
38 self.__dict__['_target'] = value |
|
39 else: |
|
40 if self._target is None: |
|
41 self._import_settings() |
|
42 setattr(self._target, name, value) |
|
43 |
|
44 def _import_settings(self): |
|
45 """ |
|
46 Load the settings module pointed to by the environment variable. This |
|
47 is used the first time we need any settings at all, if the user has not |
|
48 previously configured the settings manually. |
|
49 """ |
|
50 try: |
|
51 settings_module = os.environ[ENVIRONMENT_VARIABLE] |
|
52 if not settings_module: # If it's set but is an empty string. |
|
53 raise KeyError |
|
54 except KeyError: |
|
55 # NOTE: This is arguably an EnvironmentError, but that causes |
|
56 # problems with Python's interactive help. |
|
57 raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE) |
|
58 |
|
59 self._target = Settings(settings_module) |
|
60 |
|
61 def configure(self, default_settings=global_settings, **options): |
|
62 """ |
|
63 Called to manually configure the settings. The 'default_settings' |
|
64 parameter sets where to retrieve any unspecified values from (its |
|
65 argument must support attribute access (__getattr__)). |
|
66 """ |
|
67 if self._target != None: |
|
68 raise RuntimeError, 'Settings already configured.' |
|
69 holder = UserSettingsHolder(default_settings) |
|
70 for name, value in options.items(): |
|
71 setattr(holder, name, value) |
|
72 self._target = holder |
|
73 |
|
74 class Settings(object): |
|
75 def __init__(self, settings_module): |
|
76 # update this dict from global settings (but only for ALL_CAPS settings) |
|
77 for setting in dir(global_settings): |
|
78 if setting == setting.upper(): |
|
79 setattr(self, setting, getattr(global_settings, setting)) |
|
80 |
|
81 # store the settings module in case someone later cares |
|
82 self.SETTINGS_MODULE = settings_module |
|
83 |
|
84 try: |
|
85 mod = __import__(self.SETTINGS_MODULE, {}, {}, ['']) |
|
86 except ImportError, e: |
|
87 raise ImportError, "Could not import settings '%s' (Is it on sys.path? Does it have syntax errors?): %s" % (self.SETTINGS_MODULE, e) |
|
88 |
|
89 # Settings that should be converted into tuples if they're mistakenly entered |
|
90 # as strings. |
|
91 tuple_settings = ("INSTALLED_APPS", "TEMPLATE_DIRS") |
|
92 |
|
93 for setting in dir(mod): |
|
94 if setting == setting.upper(): |
|
95 setting_value = getattr(mod, setting) |
|
96 if setting in tuple_settings and type(setting_value) == str: |
|
97 setting_value = (setting_value,) # In case the user forgot the comma. |
|
98 setattr(self, setting, setting_value) |
|
99 |
|
100 # Expand entries in INSTALLED_APPS like "django.contrib.*" to a list |
|
101 # of all those apps. |
|
102 new_installed_apps = [] |
|
103 for app in self.INSTALLED_APPS: |
|
104 if app.endswith('.*'): |
|
105 appdir = os.path.dirname(__import__(app[:-2], {}, {}, ['']).__file__) |
|
106 for d in os.listdir(appdir): |
|
107 if d.isalpha() and os.path.isdir(os.path.join(appdir, d)): |
|
108 new_installed_apps.append('%s.%s' % (app[:-2], d)) |
|
109 else: |
|
110 new_installed_apps.append(app) |
|
111 self.INSTALLED_APPS = new_installed_apps |
|
112 |
|
113 if hasattr(time, 'tzset'): |
|
114 # Move the time zone info into os.environ. See ticket #2315 for why |
|
115 # we don't do this unconditionally (breaks Windows). |
|
116 os.environ['TZ'] = self.TIME_ZONE |
|
117 time.tzset() |
|
118 |
|
119 def get_all_members(self): |
|
120 return dir(self) |
|
121 |
|
122 class UserSettingsHolder(object): |
|
123 """ |
|
124 Holder for user configured settings. |
|
125 """ |
|
126 # SETTINGS_MODULE doesn't make much sense in the manually configured |
|
127 # (standalone) case. |
|
128 SETTINGS_MODULE = None |
|
129 |
|
130 def __init__(self, default_settings): |
|
131 """ |
|
132 Requests for configuration variables not in this class are satisfied |
|
133 from the module specified in default_settings (if possible). |
|
134 """ |
|
135 self.default_settings = default_settings |
|
136 |
|
137 def __getattr__(self, name): |
|
138 return getattr(self.default_settings, name) |
|
139 |
|
140 def get_all_members(self): |
|
141 return dir(self) + dir(self.default_settings) |
|
142 |
|
143 settings = LazySettings() |
|
144 |