Author: mtredinnick
Date: 2009-03-01 22:57:03 -0600 (Sun, 01 Mar 2009)
New Revision: 9947

Modified:
   django/branches/releases/1.0.X/django/conf/__init__.py
   django/branches/releases/1.0.X/django/core/files/storage.py
   django/branches/releases/1.0.X/django/utils/functional.py
Log:
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).

Modified: django/branches/releases/1.0.X/django/conf/__init__.py
===================================================================
--- django/branches/releases/1.0.X/django/conf/__init__.py      2009-03-02 
04:48:47 UTC (rev 9946)
+++ django/branches/releases/1.0.X/django/conf/__init__.py      2009-03-02 
04:57:03 UTC (rev 9947)
@@ -8,40 +8,19 @@
 
 import os
 import time     # Needed for Windows
+
 from django.conf import global_settings
+from django.utils.functional import LazyObject
 
 ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
 
-class LazySettings(object):
+class LazySettings(LazyObject):
     """
     A lazy proxy for either global Django settings or a custom settings object.
     The user can manually configure settings prior to using them. Otherwise,
     Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
     """
-    def __init__(self):
-        # _target must be either None or something that supports attribute
-        # access (getattr, hasattr, etc).
-        self._target = None
-
-    def __getattr__(self, name):
-        if self._target is None:
-            self._import_settings()
-        if name == '__members__':
-            # Used to implement dir(obj), for example.
-            return self._target.get_all_members()
-        return getattr(self._target, name)
-
-    def __setattr__(self, name, value):
-        if name == '_target':
-            # Assign directly to self.__dict__, because otherwise we'd call
-            # __setattr__(), which would be an infinite loop.
-            self.__dict__['_target'] = value
-        else:
-            if self._target is None:
-                self._import_settings()
-            setattr(self._target, name, value)
-
-    def _import_settings(self):
+    def _setup(self):
         """
         Load the settings module pointed to by the environment variable. This
         is used the first time we need any settings at all, if the user has not
@@ -56,7 +35,7 @@
             # problems with Python's interactive help.
             raise ImportError("Settings cannot be imported, because 
environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
 
-        self._target = Settings(settings_module)
+        self._wrapped = Settings(settings_module)
 
     def configure(self, default_settings=global_settings, **options):
         """
@@ -69,13 +48,13 @@
         holder = UserSettingsHolder(default_settings)
         for name, value in options.items():
             setattr(holder, name, value)
-        self._target = holder
+        self._wrapped = holder
 
     def configured(self):
         """
         Returns True if the settings have already been configured.
         """
-        return bool(self._target)
+        return bool(self._wrapped)
     configured = property(configured)
 
 class Settings(object):

Modified: django/branches/releases/1.0.X/django/core/files/storage.py
===================================================================
--- django/branches/releases/1.0.X/django/core/files/storage.py 2009-03-02 
04:48:47 UTC (rev 9946)
+++ django/branches/releases/1.0.X/django/core/files/storage.py 2009-03-02 
04:57:03 UTC (rev 9947)
@@ -4,11 +4,12 @@
 
 from django.conf import settings
 from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
+from django.core.files import locks, File
+from django.core.files.move import file_move_safe
 from django.utils.encoding import force_unicode
+from django.utils.functional import LazyObject
 from django.utils.text import get_valid_filename
 from django.utils._os import safe_join
-from django.core.files import locks, File
-from django.core.files.move import file_move_safe
 
 __all__ = ('Storage', 'FileSystemStorage', 'DefaultStorage', 'default_storage')
 
@@ -40,7 +41,7 @@
         # Get the proper name for the file, as it will actually be saved.
         if name is None:
             name = content.name
-        
+
         name = self.get_available_name(name)
         name = self._save(name, content)
 
@@ -116,12 +117,20 @@
         """
         raise NotImplementedError()
 
+    # Needed by django.utils.functional.LazyObject (via DefaultStorage).
+    def get_all_members(self):
+        return self.__members__
+
 class FileSystemStorage(Storage):
     """
     Standard filesystem storage
     """
 
-    def __init__(self, location=settings.MEDIA_ROOT, 
base_url=settings.MEDIA_URL):
+    def __init__(self, location=None, base_url=None):
+        if location is None:
+            location = settings.MEDIA_ROOT
+        if base_url is None:
+            base_url = settings.MEDIA_URL
         self.location = os.path.abspath(location)
         self.base_url = base_url
 
@@ -172,10 +181,10 @@
             else:
                 # OK, the file save worked. Break out of the loop.
                 break
-        
+
         if settings.FILE_UPLOAD_PERMISSIONS is not None:
             os.chmod(full_path, settings.FILE_UPLOAD_PERMISSIONS)
-        
+
         return name
 
     def delete(self, name):
@@ -212,7 +221,9 @@
             raise ValueError("This file is not accessible via a URL.")
         return urlparse.urljoin(self.base_url, name).replace('\\', '/')
 
-def get_storage_class(import_path):
+def get_storage_class(import_path=None):
+    if import_path is None:
+        import_path = settings.DEFAULT_FILE_STORAGE
     try:
         dot = import_path.rindex('.')
     except ValueError:
@@ -227,5 +238,8 @@
     except AttributeError:
         raise ImproperlyConfigured('Storage module "%s" does not define a "%s" 
class.' % (module, classname))
 
-DefaultStorage = get_storage_class(settings.DEFAULT_FILE_STORAGE)
+class DefaultStorage(LazyObject):
+    def _setup(self):
+        self._wrapped = get_storage_class()()
+
 default_storage = DefaultStorage()

Modified: django/branches/releases/1.0.X/django/utils/functional.py
===================================================================
--- django/branches/releases/1.0.X/django/utils/functional.py   2009-03-02 
04:48:47 UTC (rev 9946)
+++ django/branches/releases/1.0.X/django/utils/functional.py   2009-03-02 
04:57:03 UTC (rev 9947)
@@ -251,3 +251,39 @@
             return func(*args, **kwargs)
         return lazy(func, *resultclasses)(*args, **kwargs)
     return wraps(func)(wrapper)
+
+class LazyObject(object):
+    """
+    A wrapper for another class that can be used to delay instantiation of the
+    wrapped class.
+
+    This is useful, for example, if the wrapped class needs to use Django
+    settings at creation time: we want to permit it to be imported without
+    accessing settings.
+    """
+    def __init__(self):
+        self._wrapped = None
+
+    def __getattr__(self, name):
+        if self._wrapped is None:
+            self._setup()
+        if name == "__members__":
+            # Used to implement dir(obj)
+            return self._wrapped.get_all_members()
+        return getattr(self._wrapped, name)
+
+    def __setattr__(self, name, value):
+        if name == "_wrapped":
+            # Assign to __dict__ to avoid infinite __setattr__ loops.
+            self.__dict__["_wrapped"] = value
+        else:
+            if self._wrapped is None:
+                self._setup()
+            setattr(self._wrapped, name, value)
+
+    def _setup(self):
+        """
+        Must be implemented by subclasses to initialise the wrapped object.
+        """
+        raise NotImplementedError
+


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to