Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Removed some import-time dependencies on Django's settings.

Now you can import the file storage stuff and still call settings.configure()
afterwards. There is still one import-time usage of settings in
django.contrib.comments, but that's unavoidable.

Backport of r9945 and r9946 from trunk (this is needed in order to fix #8193 in
a clean fashion, which is why it's being backported).

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@9947 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 32be118081fab4ec62412d2dcb97b7d835b8d109 1 parent 9576353
Malcolm Tredinnick authored March 02, 2009
35  django/conf/__init__.py
@@ -8,40 +8,19 @@
8 8
 
9 9
 import os
10 10
 import time     # Needed for Windows
  11
+
11 12
 from django.conf import global_settings
  13
+from django.utils.functional import LazyObject
12 14
 
13 15
 ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
14 16
 
15  
-class LazySettings(object):
  17
+class LazySettings(LazyObject):
16 18
     """
17 19
     A lazy proxy for either global Django settings or a custom settings object.
18 20
     The user can manually configure settings prior to using them. Otherwise,
19 21
     Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
20 22
     """
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):
  23
+    def _setup(self):
45 24
         """
46 25
         Load the settings module pointed to by the environment variable. This
47 26
         is used the first time we need any settings at all, if the user has not
@@ -56,7 +35,7 @@ def _import_settings(self):
56 35
             # problems with Python's interactive help.
57 36
             raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
58 37
 
59  
-        self._target = Settings(settings_module)
  38
+        self._wrapped = Settings(settings_module)
60 39
 
61 40
     def configure(self, default_settings=global_settings, **options):
62 41
         """
@@ -69,13 +48,13 @@ def configure(self, default_settings=global_settings, **options):
69 48
         holder = UserSettingsHolder(default_settings)
70 49
         for name, value in options.items():
71 50
             setattr(holder, name, value)
72  
-        self._target = holder
  51
+        self._wrapped = holder
73 52
 
74 53
     def configured(self):
75 54
         """
76 55
         Returns True if the settings have already been configured.
77 56
         """
78  
-        return bool(self._target)
  57
+        return bool(self._wrapped)
79 58
     configured = property(configured)
80 59
 
81 60
 class Settings(object):
30  django/core/files/storage.py
@@ -4,11 +4,12 @@
4 4
 
5 5
 from django.conf import settings
6 6
 from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
  7
+from django.core.files import locks, File
  8
+from django.core.files.move import file_move_safe
7 9
 from django.utils.encoding import force_unicode
  10
+from django.utils.functional import LazyObject
8 11
 from django.utils.text import get_valid_filename
9 12
 from django.utils._os import safe_join
10  
-from django.core.files import locks, File
11  
-from django.core.files.move import file_move_safe
12 13
 
13 14
 __all__ = ('Storage', 'FileSystemStorage', 'DefaultStorage', 'default_storage')
14 15
 
@@ -40,7 +41,7 @@ def save(self, name, content):
40 41
         # Get the proper name for the file, as it will actually be saved.
41 42
         if name is None:
42 43
             name = content.name
43  
-        
  44
+
44 45
         name = self.get_available_name(name)
45 46
         name = self._save(name, content)
46 47
 
@@ -116,12 +117,20 @@ def url(self, name):
116 117
         """
117 118
         raise NotImplementedError()
118 119
 
  120
+    # Needed by django.utils.functional.LazyObject (via DefaultStorage).
  121
+    def get_all_members(self):
  122
+        return self.__members__
  123
+
119 124
 class FileSystemStorage(Storage):
120 125
     """
121 126
     Standard filesystem storage
122 127
     """
123 128
 
124  
-    def __init__(self, location=settings.MEDIA_ROOT, base_url=settings.MEDIA_URL):
  129
+    def __init__(self, location=None, base_url=None):
  130
+        if location is None:
  131
+            location = settings.MEDIA_ROOT
  132
+        if base_url is None:
  133
+            base_url = settings.MEDIA_URL
125 134
         self.location = os.path.abspath(location)
126 135
         self.base_url = base_url
127 136
 
@@ -172,10 +181,10 @@ def _save(self, name, content):
172 181
             else:
173 182
                 # OK, the file save worked. Break out of the loop.
174 183
                 break
175  
-        
  184
+
176 185
         if settings.FILE_UPLOAD_PERMISSIONS is not None:
177 186
             os.chmod(full_path, settings.FILE_UPLOAD_PERMISSIONS)
178  
-        
  187
+
179 188
         return name
180 189
 
181 190
     def delete(self, name):
@@ -212,7 +221,9 @@ def url(self, name):
212 221
             raise ValueError("This file is not accessible via a URL.")
213 222
         return urlparse.urljoin(self.base_url, name).replace('\\', '/')
214 223
 
215  
-def get_storage_class(import_path):
  224
+def get_storage_class(import_path=None):
  225
+    if import_path is None:
  226
+        import_path = settings.DEFAULT_FILE_STORAGE
216 227
     try:
217 228
         dot = import_path.rindex('.')
218 229
     except ValueError:
@@ -227,5 +238,8 @@ def get_storage_class(import_path):
227 238
     except AttributeError:
228 239
         raise ImproperlyConfigured('Storage module "%s" does not define a "%s" class.' % (module, classname))
229 240
 
230  
-DefaultStorage = get_storage_class(settings.DEFAULT_FILE_STORAGE)
  241
+class DefaultStorage(LazyObject):
  242
+    def _setup(self):
  243
+        self._wrapped = get_storage_class()()
  244
+
231 245
 default_storage = DefaultStorage()
36  django/utils/functional.py
@@ -251,3 +251,39 @@ def wrapper(*args, **kwargs):
251 251
             return func(*args, **kwargs)
252 252
         return lazy(func, *resultclasses)(*args, **kwargs)
253 253
     return wraps(func)(wrapper)
  254
+
  255
+class LazyObject(object):
  256
+    """
  257
+    A wrapper for another class that can be used to delay instantiation of the
  258
+    wrapped class.
  259
+
  260
+    This is useful, for example, if the wrapped class needs to use Django
  261
+    settings at creation time: we want to permit it to be imported without
  262
+    accessing settings.
  263
+    """
  264
+    def __init__(self):
  265
+        self._wrapped = None
  266
+
  267
+    def __getattr__(self, name):
  268
+        if self._wrapped is None:
  269
+            self._setup()
  270
+        if name == "__members__":
  271
+            # Used to implement dir(obj)
  272
+            return self._wrapped.get_all_members()
  273
+        return getattr(self._wrapped, name)
  274
+
  275
+    def __setattr__(self, name, value):
  276
+        if name == "_wrapped":
  277
+            # Assign to __dict__ to avoid infinite __setattr__ loops.
  278
+            self.__dict__["_wrapped"] = value
  279
+        else:
  280
+            if self._wrapped is None:
  281
+                self._setup()
  282
+            setattr(self._wrapped, name, value)
  283
+
  284
+    def _setup(self):
  285
+        """
  286
+        Must be implemented by subclasses to initialise the wrapped object.
  287
+        """
  288
+        raise NotImplementedError
  289
+

0 notes on commit 32be118

Please sign in to comment.
Something went wrong with that request. Please try again.