Decorator and context manager to override settings

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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

More like this

  1. Modify requests in your unit tests (improvement on RequestFactory) by vaughnkoch 3 years, 6 months ago
  2. Automatic testing of add and changelist admin views by Taifu 2 years, 8 months ago
  3. EasyFeed class by limodou 7 years, 1 month ago
  4. Format transition middleware by limodou 7 years, 1 month ago
  5. Testrunner with testmodels by nfg 4 years, 2 months ago

Comments

tartley (on August 19, 2011):

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?

#

(Forgotten your password?)