diff --git a/configurations/base.py b/configurations/base.py index c9a678a..aa7deff 100644 --- a/configurations/base.py +++ b/configurations/base.py @@ -59,5 +59,9 @@ class Settings(six.with_metaclass(SettingsBase)): """ @classmethod - def setup(cls): + def pre_setup(cls): + pass + + @classmethod + def post_setup(cls): pass diff --git a/configurations/importer.py b/configurations/importer.py index ada3411..76a8104 100644 --- a/configurations/importer.py +++ b/configurations/importer.py @@ -160,6 +160,7 @@ class SettingsLoader(object): else: mod = imp.load_module(fullname, *self.location) cls_path = '%s.%s' % (mod.__name__, self.name) + try: cls = getattr(mod, self.name) except AttributeError as err: # pragma: no cover @@ -167,9 +168,10 @@ class SettingsLoader(object): "While trying to find the '%s' settings in module '%s'" % (self.name, mod.__package__)) try: - cls.setup() + cls.pre_setup() except Exception as err: - reraise(err, "While calling '%s.setup()'" % cls_path) + reraise(err, "While calling '%s.pre_setup()'" % cls_path) + try: obj = cls() except Exception as err: @@ -193,4 +195,10 @@ class SettingsLoader(object): setattr(mod, name, value) setattr(mod, 'CONFIGURATION', '%s.%s' % (fullname, self.name)) + + try: + cls.post_setup() + except Exception as err: + reraise(err, "While calling '%s.post_setup()'" % cls_path) + return mod diff --git a/configurations/tests/settings/main.py b/configurations/tests/settings/main.py index b5cc1d9..c5ee238 100644 --- a/configurations/tests/settings/main.py +++ b/configurations/tests/settings/main.py @@ -54,5 +54,11 @@ class Test(Settings): return 5 @classmethod - def setup(cls): - cls.SETUP_TEST_SETTING = 6 + def pre_setup(cls): + cls.PRE_SETUP_TEST_SETTING = 6 + + @classmethod + def post_setup(cls): + cls.POST_SETUP_TEST_SETTING = 7 + from django.conf import settings + settings.POST_SETUP_TEST_SETTING = 8 diff --git a/configurations/tests/test_main.py b/configurations/tests/test_main.py index 751a79c..55f00d9 100644 --- a/configurations/tests/test_main.py +++ b/configurations/tests/test_main.py @@ -25,7 +25,8 @@ class MainTests(TestCase): global_settings.TEMPLATE_CONTEXT_PROCESSORS + ( 'configurations.tests.settings.base.test_callback', )) - self.assertEqual(main.SETUP_TEST_SETTING, 6) + self.assertEqual(main.PRE_SETUP_TEST_SETTING, 6) + self.assertRaises(AttributeError, lambda: main.POST_SETUP_TEST_SETTING) def test_global_arrival(self): from django.conf import settings @@ -35,7 +36,8 @@ class MainTests(TestCase): self.assertTrue(lambda: callable(settings.PRISTINE_LAMBDA_SETTING)) self.assertNotEqual(settings.PRISTINE_FUNCTION_SETTING, 5) self.assertTrue(lambda: callable(settings.PRISTINE_FUNCTION_SETTING)) - self.assertEqual(settings.SETUP_TEST_SETTING, 6) + self.assertEqual(settings.PRE_SETUP_TEST_SETTING, 6) + self.assertEqual(settings.POST_SETUP_TEST_SETTING, 8) @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 82ede19..c5498f3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -160,9 +160,10 @@ Setup methods .. versionadded:: 0.3 -If there is something required to be set up after all the settings have been -loaded please override the ``setup`` class method like so (don't forget -to apply the Python ``@classmethod`` decorator:: +If there is something required to be set up before or after the settings +loading happens, please override the ``pre_setup`` or ``post_setup`` +class methods like so (don't forget to apply the Python ``@classmethod`` +decorator:: from configurations import Settings @@ -170,11 +171,22 @@ to apply the Python ``@classmethod`` decorator:: # ... @classmethod - def setup(cls): + def pre_setup(cls): if something.completely.different(): cls.DEBUG = True -Or do something unrelated to your settings, like connecting to a database:: + @classmethod + def post_setup(cls): + print("done setting up! \o/") + +As you can see above the ``pre_setup`` method can also be used to +programmatically change a class attribute of the settings class and it +will be taken into account when doing the rest of the settings setup. +Of course that won't work for ``post_setup`` since that's when the +settings setup is already done. + +In fact you can easily do something unrelated to settings, like +connecting to a database:: from configurations import Settings @@ -182,10 +194,22 @@ Or do something unrelated to your settings, like connecting to a database:: # ... @classmethod - def setup(cls): + def post_setup(cls): import mango mango.connect('enterprise') + +.. warning:: + + You could do the same by overriding the ``__init__`` method of your + settings class but this may cause hard to debug errors because + at the time the ``__init__`` method is called (during Django startup) + the Django setting system isn't fully loaded yet. + + So anything you do in ``__init__`` that may require + ``django.conf.settings`` or Django models there is a good chance it + won't work. Use the ``post_setup`` method for that instead. + Alternatives ------------