Ticket #14264: 14264.diff
File 14264.diff, 11.4 KB (added by , 13 years ago) |
---|
-
django/conf/__init__.py
=== modified file 'django/conf/__init__.py'
9 9 import os 10 10 import re 11 11 import time # Needed for Windows 12 import types 12 13 import warnings 13 14 14 15 from django.conf import global_settings … … 49 50 """ 50 51 if self._wrapped is not empty: 51 52 raise RuntimeError('Settings already configured.') 52 holder = UserSettingsHolder(default_settings) 53 for name, value in options.items(): 54 setattr(holder, name, value) 53 holder = UserSettingsHolder(default_settings=default_settings, 54 extra_settings=options) 55 55 self._wrapped = holder 56 56 57 57 @property … … 62 62 return self._wrapped is not empty 63 63 64 64 65 class BaseSettings(object):65 class Settings(object): 66 66 """ 67 67 Common logic for settings whether set by a module or by the user. 68 68 """ 69 70 # Settings that should be converted into tuples if they're mistakenly 71 # entered as strings. 72 tuple_settings = ("INSTALLED_APPS", "TEMPLATE_DIRS") 73 # Flag to specify whether or not changes should be made to environment. 74 environ_changes_allowed = True 75 76 def __init__(self, settings_module=None, default_settings=global_settings, 77 extra_settings=None): 78 if settings_module: 79 # store the settings module in case someone later cares 80 self.SETTINGS_MODULE = settings_module 81 self.initialize([default_settings, settings_module, extra_settings]) 82 self.post_setup() 83 69 84 def __setattr__(self, name, value): 70 85 if name in ("MEDIA_URL", "STATIC_URL") and value and not value.endswith('/'): 71 86 warnings.warn("If set, %s must end with a slash" % name, … … 75 90 "use STATIC_URL instead.", DeprecationWarning) 76 91 object.__setattr__(self, name, value) 77 92 78 79 class Settings(BaseSettings): 80 def __init__(self, settings_module): 81 # update this dict from global settings (but only for ALL_CAPS settings) 82 for setting in dir(global_settings): 83 if setting == setting.upper(): 84 setattr(self, setting, getattr(global_settings, setting)) 85 86 # store the settings module in case someone later cares 87 self.SETTINGS_MODULE = settings_module 93 def initialize(self, settings_objs): 94 """ 95 Initializes this settings object based on attributes/keys from the 96 objects in the settings_objs list. 97 98 If the item is a string, then attempt to import a module by name. 99 Once we have a module object, or if a module object was passed, then 100 then construct a dictionary from the attributes in the module. 101 Once we have a dictionary, or if a dictionary was passed, then set all 102 ALL CAPS keys and values as attributes on this settings object. 103 """ 104 for obj in settings_objs: 105 if not obj: 106 continue 107 if isinstance(obj, basestring): 108 obj = self._import_module(obj) 109 if isinstance(obj, types.ModuleType): 110 obj = self._dict_from_module(obj) 111 # obj should now be a dictionary. 112 for setting, value in obj.iteritems(): 113 # Only set attributes that are (ALL CAPS). 114 if setting == setting.upper(): 115 setattr(self, setting, value) 116 117 def _import_module(self, name): 88 118 89 119 try: 90 120 mod = importlib.import_module(self.SETTINGS_MODULE) 91 121 except ImportError, e: 92 raise ImportError("Could not import settings '%s' (Is it on sys.path?): %s" % (self.SETTINGS_MODULE, e)) 93 94 # Settings that should be converted into tuples if they're mistakenly entered 95 # as strings. 96 tuple_settings = ("INSTALLED_APPS", "TEMPLATE_DIRS") 97 98 for setting in dir(mod): 99 if setting == setting.upper(): 100 setting_value = getattr(mod, setting) 101 if setting in tuple_settings and type(setting_value) == str: 102 setting_value = (setting_value,) # In case the user forgot the comma. 103 setattr(self, setting, setting_value) 104 105 # Expand entries in INSTALLED_APPS like "django.contrib.*" to a list 106 # of all those apps. 122 raise ImportError( 123 "Could not import settings '%s' (Is it on sys.path?): %s" 124 % (self.SETTINGS_MODULE, e)) 125 return mod 126 127 def _dict_from_module(self, module): 128 d = {} 129 for setting in dir(module): 130 d[setting] = getattr(module, setting) 131 return d 132 133 def post_setup(self): 134 self._correct_tuple_settings() 135 # Must remain after call to correct tuple settings, because 136 # INSTALLED_APPS is a tuple setting. 137 self._expand_installed_apps() 138 self._set_tz() 139 self._setup_logging() 140 141 def _expand_installed_apps(self): 142 """ 143 Expand glob entries in INSTALLED_APPS, e.g. "django.contrib.*", to a 144 list of all those apps. 145 """ 107 146 new_installed_apps = [] 108 147 for app in self.INSTALLED_APPS: 109 148 if app.endswith('.*'): … … 119 158 new_installed_apps.append(app) 120 159 self.INSTALLED_APPS = new_installed_apps 121 160 161 def _correct_tuple_settings(self): 162 """ 163 For settings that are meant to be tuples, auto correct if user forgot 164 trailing comma on a single value. 165 """ 166 for setting in self.tuple_settings: 167 value = getattr(self, setting, None) 168 if isinstance(value, basestring): 169 setattr(self, setting, (value,)) 170 171 def _set_tz(self): 172 if not self.environ_changes_allowed: 173 return 122 174 if hasattr(time, 'tzset') and self.TIME_ZONE: 123 175 # When we can, attempt to validate the timezone. If we can't find 124 176 # this file, no check happens and it's harmless. … … 131 183 os.environ['TZ'] = self.TIME_ZONE 132 184 time.tzset() 133 185 186 def _setup_logging(self): 134 187 # Settings are configured, so we can set up the logger if required 135 188 if self.LOGGING_CONFIG: 136 189 # First find the logging configuration function ... … … 145 198 logging_config_func(self.LOGGING) 146 199 147 200 148 class UserSettingsHolder( BaseSettings):201 class UserSettingsHolder(Settings): 149 202 """ 150 203 Holder for user configured settings. 151 204 """ 152 205 # SETTINGS_MODULE doesn't make much sense in the manually configured 153 206 # (standalone) case. 154 207 SETTINGS_MODULE = None 208 # Don't make any modifications to the process environment variables. 209 environ_changes_allowed = False 155 210 156 def __init__(self, default_settings):211 def __init__(self, *args, **kwargs): 157 212 """ 158 213 Requests for configuration variables not in this class are satisfied 159 214 from the module specified in default_settings (if possible). 160 215 """ 161 self.default_settings = default_settings 216 self.default_settings = kwargs['default_settings'] 217 super(UserSettingsHolder, self).__init__(*args, **kwargs) 162 218 163 219 def __getattr__(self, name): 164 220 return getattr(self.default_settings, name) -
tests/regressiontests/app_loading/test_settings.py
=== modified file 'tests/regressiontests/app_loading/test_settings.py'
1 1 INSTALLED_APPS = ( 2 2 'parent.*', 3 3 ) 4 5 TIME_ZONE='Europe/London' -
tests/regressiontests/app_loading/tests.py
=== modified file 'tests/regressiontests/app_loading/tests.py'
3 3 import sys 4 4 import time 5 5 6 from django.conf import Settings 6 from django.conf import Settings, LazySettings 7 7 from django.db.models.loading import cache, load_app, get_model, get_models 8 8 from django.utils.unittest import TestCase 9 9 10 10 11 class InstalledAppsGlobbingTest(TestCase):12 def setUp(self):13 self.OLD_SYS_PATH = sys.path[:]14 sys.path.append(os.path.dirname(os.path.abspath(__file__)))15 self.OLD_TZ = os.environ.get("TZ")16 17 def test_globbing(self):18 settings = Settings('test_settings')19 self.assertEqual(settings.INSTALLED_APPS, ['parent.app', 'parent.app1', 'parent.app_2'])20 21 def tearDown(self):22 sys.path = self.OLD_SYS_PATH23 if hasattr(time, "tzset") and self.OLD_TZ:24 os.environ["TZ"] = self.OLD_TZ25 time.tzset()26 27 28 11 class EggLoadingTest(TestCase): 29 12 30 13 def setUp(self): … … 123 106 self.assertEqual( 124 107 set(NotInstalledModel._meta.get_all_field_names()), 125 108 set(["id", "relatedmodel", "m2mrelatedmodel"])) 109 110 111 class SettingsMixin(object): 112 113 def setUp(self): 114 self.OLD_SYS_PATH = sys.path[:] 115 sys.path.append(os.path.dirname(os.path.abspath(__file__))) 116 self.OLD_TZ = os.environ.get("TZ") 117 118 def tearDown(self): 119 sys.path = self.OLD_SYS_PATH 120 if hasattr(time, "tzset") and self.OLD_TZ: 121 os.environ["TZ"] = self.OLD_TZ 122 time.tzset() 123 124 125 class SettingsConfigureTest(SettingsMixin, TestCase): 126 """ 127 Tests for settings using settings.configure(). 128 """ 129 130 def test_installed_app_globbing(self): 131 settings = LazySettings() 132 settings.configure(INSTALLED_APPS=('parent.*',)) 133 self.assertEqual(settings.INSTALLED_APPS, ['parent.app', 'parent.app1', 'parent.app_2']) 134 135 def test_tuple_settings(self): 136 settings = LazySettings() 137 settings.configure(INSTALLED_APPS="parent.app", TEMPLATE_DIRS="foo") 138 self.assertEqual(settings.INSTALLED_APPS, ['parent.app']) 139 self.assertEqual(settings.TEMPLATE_DIRS, ('foo',)) 140 141 def test_time_zone_environ(self): 142 """ 143 Time zone environment variable shouldn't get altered. 144 """ 145 orig_tz = os.environ.get('TZ') 146 settings = LazySettings() 147 settings.configure(TIME_ZONE='Europe/London') 148 # Time zone updated, but not environment variable. 149 self.assertEqual(settings.TIME_ZONE, 'Europe/London') 150 self.assertEqual(os.environ.get('TZ'), orig_tz) 151 152 153 class SettingsTest(SettingsMixin, TestCase): 154 """ 155 Tests for settings using Settings object. 156 """ 157 158 def test_installed_app_globbing(self): 159 settings = Settings('test_settings') 160 self.assertEqual(settings.INSTALLED_APPS, ['parent.app', 'parent.app1', 'parent.app_2']) 161 162 def test_tuple_settings(self): 163 settings = Settings('tuple_settings') 164 self.assertEqual(settings.INSTALLED_APPS, ['parent.app']) 165 self.assertEqual(settings.TEMPLATE_DIRS, ('foo',)) 166 167 def test_time_zone_environ(self): 168 """ 169 Time zone environment variable shouldn't get altered. 170 """ 171 orig_tz = os.environ.get('TZ') 172 settings = Settings('test_settings') 173 self.assertEqual(settings.TIME_ZONE, 'Europe/London') 174 self.assertEqual(os.environ.get('TZ'), 'Europe/London') -
tests/regressiontests/app_loading/tuple_settings.py
=== added file 'tests/regressiontests/app_loading/tuple_settings.py'
1 # Settings file for testing correction of tuple settings. 2 INSTALLED_APPS="parent.app" 3 TEMPLATE_DIRS="foo"