from __future__ import with_statement
from django.conf import settings, UserSettingsHolder
from django.utils.functional import wraps
class override_settings(object):
"""
Acts as either a decorator, or a context manager. If it's a decorator it
takes a function and returns a wrapped function. If it's a contextmanager
it's used with the ``with`` statement. In either event entering/exiting
are called before and after, respectively, the function/block is executed.
"""
def __init__(self, **kwargs):
self.options = kwargs
self.wrapped = settings._wrapped
def __enter__(self):
self.enable()
def __exit__(self, exc_type, exc_value, traceback):
self.disable()
def __call__(self, func):
@wraps(func)
def inner(*args, **kwargs):
with self:
return func(*args, **kwargs)
return inner
def enable(self):
override = UserSettingsHolder(settings._wrapped)
for key, new_value in self.options.items():
setattr(override, key, new_value)
settings._wrapped = override
def disable(self):
settings._wrapped = self.wrapped
Comments
Hey. This is great, thanks.
Just to check I'm understanding correctly: The Django 1.2 docs specifically forbid changing settings anywhere other than in your settings files: https://docs.djangoproject.com/en/dev/topics/settings/#altering-settings-at-runtime
Is this because of the hazards of not undoing the changes that are wrought, thus leaving the application in an inconsistent state? (early-imported modules thing the settings say one thing, imports after your modification think the settings say another thing)
Does a snippet like this run the risk that any global state which depends on the modified settings, and is set within the scope of the context manager, will permanently be set to a value which is inconsistent with the rest of the application?
If so, presumably this can be avoided by not ever setting global state that depends on the values of settings - the settings should be referred to directly every time their value is needed.
Am I vaguely understanding correctly?
#