Ticket #14264: 14264.2.diff
File 14264.2.diff, 13.7 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 88 89 try: 90 mod = importlib.import_module(self.SETTINGS_MODULE) 91 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. 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 for obj in settings_objs: 99 if not obj: 100 continue 101 for setting, value in dict_from_object(obj).iteritems(): 102 setattr(self, setting, value) 103 104 def post_setup(self): 105 self._correct_tuple_settings() 106 # Must remain after call to correct tuple settings, because 107 # INSTALLED_APPS is a tuple setting. 108 self._expand_installed_apps() 109 self._set_tz() 110 self._setup_logging() 111 112 def _expand_installed_apps(self): 113 """ 114 Expand glob entries in INSTALLED_APPS, e.g. "django.contrib.*", to a 115 list of all those apps. 116 """ 107 117 new_installed_apps = [] 108 118 for app in self.INSTALLED_APPS: 109 119 if app.endswith('.*'): … … 119 129 new_installed_apps.append(app) 120 130 self.INSTALLED_APPS = new_installed_apps 121 131 132 def _correct_tuple_settings(self): 133 """ 134 For settings that are meant to be tuples, auto correct if user forgot 135 trailing comma on a single value. 136 """ 137 for setting in self.tuple_settings: 138 value = getattr(self, setting, None) 139 if isinstance(value, basestring): 140 setattr(self, setting, (value,)) 141 142 def _set_tz(self): 143 if not self.environ_changes_allowed: 144 return 122 145 if hasattr(time, 'tzset') and self.TIME_ZONE: 123 146 # When we can, attempt to validate the timezone. If we can't find 124 147 # this file, no check happens and it's harmless. … … 131 154 os.environ['TZ'] = self.TIME_ZONE 132 155 time.tzset() 133 156 157 def _setup_logging(self): 134 158 # Settings are configured, so we can set up the logger if required 135 159 if self.LOGGING_CONFIG: 136 160 # First find the logging configuration function ... … … 145 169 logging_config_func(self.LOGGING) 146 170 147 171 148 class UserSettingsHolder( BaseSettings):172 class UserSettingsHolder(Settings): 149 173 """ 150 174 Holder for user configured settings. 151 175 """ 152 176 # SETTINGS_MODULE doesn't make much sense in the manually configured 153 177 # (standalone) case. 154 178 SETTINGS_MODULE = None 155 156 def __init__(self, default_settings): 157 """ 158 Requests for configuration variables not in this class are satisfied 159 from the module specified in default_settings (if possible). 160 """ 161 self.default_settings = default_settings 162 163 def __getattr__(self, name): 164 return getattr(self.default_settings, name) 165 166 def __dir__(self): 167 return self.__dict__.keys() + dir(self.default_settings) 168 169 # For Python < 2.6: 170 __members__ = property(lambda self: self.__dir__()) 179 # Don't make any modifications to the process environment variables. 180 environ_changes_allowed = False 181 171 182 172 183 settings = LazySettings() 173 184 174 185 186 def import_module(name): 187 try: 188 mod = importlib.import_module(name) 189 except ImportError, e: 190 raise ImportError( 191 "Could not import settings '%s' (Is it on sys.path?): %s" 192 % (name, e)) 193 return mod 194 195 196 def dict_from_object(obj): 197 """ 198 Return a dictionary of obj's attributes, where obj can be one of: 199 200 * A dictionary 201 * A string containing the name of a settings module 202 * A Settings instance 203 * A module 204 205 Only attributes/keys that are ALL CAPS are returned. 206 """ 207 if isinstance(obj, basestring): 208 obj = import_module(obj) 209 if not isinstance(obj, dict): 210 obj = dict([(attr, getattr(obj, attr)) for attr in dir(obj)]) 211 212 # Only keep attributes that are (ALL CAPS). 213 keep = lambda k: k == k.upper() 214 return dict([(k, v) for k, v in obj.iteritems() if keep(k)]) 215 175 216 176 217 def compat_patch_logging_config(logging_config): 177 218 """ -
django/core/management/commands/diffsettings.py
=== modified file 'django/core/management/commands/diffsettings.py'
1 1 from django.core.management.base import NoArgsCommand 2 2 3 def module_to_dict(module, omittable=lambda k: k.startswith('_')):4 "Converts a module namespace to a Python dictionary. Used by get_settings_diff."5 return dict([(k, repr(v)) for k, v in module.__dict__.items() if not omittable(k)])6 3 7 4 class Command(NoArgsCommand): 8 5 help = """Displays differences between the current settings.py and Django's … … 13 10 14 11 def handle_noargs(self, **options): 15 12 # Inspired by Postfix's "postconf -n". 16 from django.conf import settings, global_settings 13 from django.conf import settings, global_settings, dict_from_object 17 14 18 15 # Because settings are imported lazily, we need to explicitly load them. 19 16 settings._setup() 20 17 21 user_settings = module_to_dict(settings._wrapped)22 default_settings = module_to_dict(global_settings)18 user_settings = dict_from_object(settings._wrapped) 19 default_settings = dict_from_object(global_settings) 23 20 24 21 output = [] 25 22 keys = user_settings.keys() 26 23 keys.sort() 27 24 for key in keys: 28 25 if key not in default_settings: 29 output.append("%s = % s###" % (key, user_settings[key]))26 output.append("%s = %r ###" % (key, user_settings[key])) 30 27 elif user_settings[key] != default_settings[key]: 31 output.append("%s = % s" % (key, user_settings[key]))28 output.append("%s = %r" % (key, user_settings[key])) 32 29 return '\n'.join(output) -
django/test/utils.py
=== modified file 'django/test/utils.py'
221 221 return inner 222 222 223 223 def enable(self): 224 override = OverrideSettingsHolder(settings._wrapped) 225 for key, new_value in self.options.items(): 226 setattr(override, key, new_value) 224 override = OverrideSettingsHolder(default_settings=settings._wrapped, 225 extra_settings=self.options) 227 226 settings._wrapped = override 228 227 229 228 def disable(self): -
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"