Skip to content

Commit

Permalink
Factor out some common pieces of django.conf.LazySettings.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
malcolmt committed Mar 2, 2009
1 parent ec71022 commit cf30712
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 29 deletions.
35 changes: 7 additions & 28 deletions django/conf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -56,7 +35,7 @@ def _import_settings(self):
# 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):
"""
Expand All @@ -69,13 +48,13 @@ def configure(self, default_settings=global_settings, **options):
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):
Expand Down
36 changes: 36 additions & 0 deletions django/utils/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,39 @@ def wrapper(*args, **kwargs):
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

2 changes: 1 addition & 1 deletion tests/regressiontests/comment_tests/tests/app_api_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def tearDown(self):
del settings.INSTALLED_APPS[-1]
settings.COMMENTS_APP = self.old_comments_app
if settings.COMMENTS_APP is None:
delattr(settings._target, 'COMMENTS_APP')
delattr(settings._wrapped, 'COMMENTS_APP')

def testGetCommentApp(self):
from regressiontests.comment_tests import custom_comments
Expand Down

0 comments on commit cf30712

Please sign in to comment.