Skip to content

Instantly share code, notes, and snippets.

@Jc2k
Created January 15, 2012 15:26
Show Gist options
  • Select an option

  • Save Jc2k/1616168 to your computer and use it in GitHub Desktop.

Select an option

Save Jc2k/1616168 to your computer and use it in GitHub Desktop.
Lazier Django Settings
class RecurseLock(object):
"""
Maintain a stack of settings referenced by LazierSetting so we can trap recursion.
We use a context manager to surround variable access, and ensure that the stack is cleared.
Error message contains a stack trace::
Setting FOO was used recursively
FOO -> BAR -> BAZ -> FOO
"""
locks = []
def __init__(self, name):
self.name = name
def __enter__(self):
if self.name in self.locks:
raise EnvironmentError('Setting "%s" was used recursively\n%s' % (self.name, " -> ".join(self.locks + [self.name])))
self.locks.append(self.name)
return self
def __exit__(self, *exc):
assert self.locks[-1] == self.name
self.locks[-1:] = []
class Dictify(object):
""" In order to use ``%s`` substitutions in strings we needing a settings module to look like a Dict """
def __init__(self, obj):
self.obj = obj
def __getattr__(self, key):
with RecurseLock(key):
return getattr(self.obj, key)
def __getitem__(self, key):
with RecurseLock(key):
return getattr(self.obj, key)
class LazierSetting(object):
"""
We don't want to perform %s substitutions on all settings, so use a special
proxy wrapper to mark strings.
You can also pass a callable and it will be called with the settings object
We alias LazierSetting as ``_`` for convenience.
"""
def __init__(self, value):
self.value = value
def render(self, settings):
if callable(self.value):
return self.value(settings)
return self.value % settings
_ = LazierSetting
def install():
""" Patch the Django settings proxy object so that any subclasses of LazierSetting are
rendered before they are returned to the caller """
from django import conf
old_get_attr = conf.LazySettings.__getattr__
def custom_get_attr(self, key):
val = old_get_attr(self, key)
if isinstance(val, LazierSetting):
return val.render(Dictify(self))
return val
conf.LazySettings.__getattr__ = custom_get_attr
from .settings import *
DOMAIN = "wibble.com"
"""
Your change to ``DOMAIN`` will be reflected in ``SUPPORT_EMAIL``::
>>> from django.conf import settings
>>> settings.SUPPORT_EMAIL
... [email protected]
"""
FOO = _("%(BAR)s")
BAR = _("%(FOO)s")
"""
When you try to access either of these you will cause an EnvironmentError::
>>> from djano.conf import settings
>>> settings.BAR
... EnvironmentError: Setting "BAR" was used recursively
... BAR -> FOO -> BAR
"""
from .lazy import _
DOMAIN = "localhost"
SUPPORT_EMAIL = _("support@%(DOMAIN)s")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment