diff --git a/CHANGES.rst b/CHANGES.rst index b9289a7..8dc01d1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -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) ^^^^^^^^^^^^^^^^^^^ diff --git a/configurations/__init__.py b/configurations/__init__.py index 1537a40..3031c22 100644 --- a/configurations/__init__.py +++ b/configurations/__init__.py @@ -1,5 +1,6 @@ # flake8: noqa from .base import Settings +from .decorators import pristine __version__ = '0.2.1' -__all__ = ['Settings'] +__all__ = ['Settings', 'pristine'] diff --git a/configurations/decorators.py b/configurations/decorators.py new file mode 100644 index 0000000..cb51197 --- /dev/null +++ b/configurations/decorators.py @@ -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) diff --git a/configurations/importer.py b/configurations/importer.py index 1a99333..72f3803 100644 --- a/configurations/importer.py +++ b/configurations/importer.py @@ -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)) diff --git a/configurations/tests/settings/main.py b/configurations/tests/settings/main.py index 448922e..ec4bda9 100644 --- a/configurations/tests/settings/main.py +++ b/configurations/tests/settings/main.py @@ -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',) diff --git a/configurations/tests/test_main.py b/configurations/tests/test_main.py index bee2dd0..ec1ad8a 100644 --- a/configurations/tests/test_main.py +++ b/configurations/tests/test_main.py @@ -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): diff --git a/docs/index.rst b/docs/index.rst index fa18a16..865e5f7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -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 ------------