Factor out some common pieces of django.conf.LazySettings.

This is in preparation for some reuse elsewhere in the core code.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9945 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2009-03-02 04:48:22 +00:00
parent ec710220dd
commit cf3071242a
3 changed files with 44 additions and 29 deletions

View File

@ -8,40 +8,19 @@ a list of all possible variables.
import os import os
import time # Needed for Windows import time # Needed for Windows
from django.conf import global_settings from django.conf import global_settings
from django.utils.functional import LazyObject
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
class LazySettings(object): class LazySettings(LazyObject):
""" """
A lazy proxy for either global Django settings or a custom settings object. A lazy proxy for either global Django settings or a custom settings object.
The user can manually configure settings prior to using them. Otherwise, The user can manually configure settings prior to using them. Otherwise,
Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE. Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
""" """
def __init__(self): def _setup(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):
""" """
Load the settings module pointed to by the environment variable. This 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 is used the first time we need any settings at all, if the user has not
@ -56,7 +35,7 @@ class LazySettings(object):
# problems with Python's interactive help. # problems with Python's interactive help.
raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE) 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): def configure(self, default_settings=global_settings, **options):
""" """
@ -69,13 +48,13 @@ class LazySettings(object):
holder = UserSettingsHolder(default_settings) holder = UserSettingsHolder(default_settings)
for name, value in options.items(): for name, value in options.items():
setattr(holder, name, value) setattr(holder, name, value)
self._target = holder self._wrapped = holder
def configured(self): def configured(self):
""" """
Returns True if the settings have already been configured. Returns True if the settings have already been configured.
""" """
return bool(self._target) return bool(self._wrapped)
configured = property(configured) configured = property(configured)
class Settings(object): class Settings(object):

View File

@ -251,3 +251,39 @@ def allow_lazy(func, *resultclasses):
return func(*args, **kwargs) return func(*args, **kwargs)
return lazy(func, *resultclasses)(*args, **kwargs) return lazy(func, *resultclasses)(*args, **kwargs)
return wraps(func)(wrapper) 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

View File

@ -41,7 +41,7 @@ class CustomCommentTest(CommentTestCase):
del settings.INSTALLED_APPS[-1] del settings.INSTALLED_APPS[-1]
settings.COMMENTS_APP = self.old_comments_app settings.COMMENTS_APP = self.old_comments_app
if settings.COMMENTS_APP is None: if settings.COMMENTS_APP is None:
delattr(settings._target, 'COMMENTS_APP') delattr(settings._wrapped, 'COMMENTS_APP')
def testGetCommentApp(self): def testGetCommentApp(self):
from regressiontests.comment_tests import custom_comments from regressiontests.comment_tests import custom_comments