Added pristine decorator to handle callable settings. Fixes #28.

This commit is contained in:
Jannis Leidel 2013-04-30 17:11:29 +02:00
parent e15070288c
commit 6596e191f0
7 changed files with 68 additions and 4 deletions

View file

@ -3,6 +3,11 @@
Changelog
---------
v0.3 (unreleased)
^^^^^^^^^^^^^^^^^
- Added ``pristine`` decorator to be able to have callables as settings.
v0.2.1 (2013-04-11)
^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,6 @@
# flake8: noqa
from .base import Settings
from .decorators import pristine
__version__ = '0.2.1'
__all__ = ['Settings']
__all__ = ['Settings', 'pristine']

View file

@ -0,0 +1,19 @@
def pristine(func):
"""
A decorator for handling pristine settings like callables.
Use it like this::
from configurations import pristine
class Develop(Settings):
@pristine
USER_CHECK(user):
return user.check_perms()
GROUP_CHECK = pristine(lambda user: user.has_group_access())
"""
func.pristine = True
return staticmethod(func)

View file

@ -161,12 +161,12 @@ class SettingsLoader(object):
"'%s.%s': %s" %
(mod.__name__, self.name, err))
for name, value in attributes:
if callable(value):
if callable(value) and not getattr(value, 'pristine', False):
try:
value = value()
except Exception as err:
raise ImproperlyConfigured(
"Couldn't execute callable '%s' in '%s.%s': %s" %
"Couldn't call '%s' in '%s.%s': %s" %
(value, mod.__name__, self.name, err))
setattr(mod, name, value)
setattr(mod, 'CONFIGURATION', '%s.%s' % (fullname, self.name))

View file

@ -1,6 +1,6 @@
import os
import uuid
from configurations import Settings
from configurations import Settings, pristine
class Test(Settings):
@ -43,6 +43,12 @@ class Test(Settings):
LAMBDA_SETTING = lambda self: 3
PRISTINE_LAMBDA_SETTING = pristine(lambda: 4)
@pristine
def PRISTINE_FUNCTION_SETTING():
return 5
def TEMPLATE_CONTEXT_PROCESSORS(self):
return Settings.TEMPLATE_CONTEXT_PROCESSORS + (
'configurations.tests.settings.base.test_callback',)

View file

@ -17,6 +17,10 @@ class MainTests(TestCase):
self.assertEqual(main.PROPERTY_SETTING, 1)
self.assertEqual(main.METHOD_SETTING, 2)
self.assertEqual(main.LAMBDA_SETTING, 3)
self.assertNotEqual(main.PRISTINE_LAMBDA_SETTING, 4)
self.assertTrue(lambda: callable(main.PRISTINE_LAMBDA_SETTING))
self.assertNotEqual(main.PRISTINE_FUNCTION_SETTING, 5)
self.assertTrue(lambda: callable(main.PRISTINE_FUNCTION_SETTING))
self.assertEqual(main.TEMPLATE_CONTEXT_PROCESSORS,
global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'configurations.tests.settings.base.test_callback',
@ -26,6 +30,10 @@ class MainTests(TestCase):
from django.conf import settings
self.assertEqual(settings.PROPERTY_SETTING, 1)
self.assertRaises(AttributeError, lambda: settings._PRIVATE_SETTING)
self.assertNotEqual(settings.PRISTINE_LAMBDA_SETTING, 4)
self.assertTrue(lambda: callable(settings.PRISTINE_LAMBDA_SETTING))
self.assertNotEqual(settings.PRISTINE_FUNCTION_SETTING, 5)
self.assertTrue(lambda: callable(settings.PRISTINE_FUNCTION_SETTING))
@patch.dict(os.environ, clear=True, DJANGO_CONFIGURATION='Test')
def test_empty_module_var(self):

View file

@ -131,6 +131,31 @@ a Settings class::
DEBUG = False
# ...
Pristines
^^^^^^^^^
.. versionadded:: 0.3
In case one of your settings itself need to be a callable, you need to
tell that django-configurations by using the ``pristine`` decorator,
e.g.::
from configurations import Settings, pristine
class Prod(Settings):
@pristine
def ACCESS_FUNCTION(user):
return user.is_staff
Lambdas work, too::
from configurations import Settings, pristine
class Prod(Settings):
ACCESS_FUNCTION = pristine(lamda user: user.is_staff)
Alternatives
------------