Skip to content
Browse files

Add the ability to specify EXTRA_* for append settings

  • Loading branch information...
1 parent fac395f commit 4dda275a7f6ff3b44ddb08470317f1597fdbaba9 @dcramer committed May 13, 2012
Showing with 115 additions and 11 deletions.
  1. +25 −1 README.rst
  2. +4 −3 logan/runner.py
  3. +28 −6 logan/settings.py
  4. +1 −0 setup.py
  5. +57 −1 tests/logan/settings/tests.py
View
26 README.rst
@@ -70,4 +70,28 @@ You'll now be able to access the ``sentry`` command as if it were django-admin.p
be configurable via an arbitrary settings file, and inherit any default settings you've specified::
# Note: run_gunicorn is provided by the gunicorn package
- sentry run_gunicorn 0.0.0.0:8000 -w 3
+ sentry run_gunicorn 0.0.0.0:8000 -w 3
+
+Extra Applications
+------------------
+
+A need might come up to allow the user to register additional settings. These will automatically apply
+based on keynames prefixed with ``EXTRA_`` assuming the base key (the latter part of the setting name) is
+of type list or tuple.
+
+For example, to register additional ``INSTALLED_APPS``, you would simply specify this in your custom
+(user) configuration::
+
+ EXTRA_APPS = (
+ 'foo.bar',
+ )
+
+This will ensure your default setting's ``INSTALLED_APPS`` do not have to be modified, and the user
+can specify additional apps with ease.
+
+If you wish to disable this functionality, simply pass ``allow_extra=False`` to ``run_app``::
+
+ run_app(
+ # ...,
+ allow_extras=False,
+ )
View
7 logan/runner.py
@@ -48,7 +48,8 @@ def parse_args(args):
def run_app(project=None, default_config_path=None, default_settings=None,
- settings_initializer=None, settings_envvar=None, initializer=None):
+ settings_initializer=None, settings_envvar=None, initializer=None,
+ allow_extras=True):
"""
:param project: should represent the canonical name for the project, generally
the same name it assigned in distutils.
@@ -123,9 +124,9 @@ def run_app(project=None, default_config_path=None, default_settings=None,
settings_mod = import_module(default_settings)
# TODO: logan should create a proxy module for its settings
management.setup_environ(settings_mod, default_settings)
- add_settings(settings_mod)
+ add_settings(settings_mod, allow_extras=allow_extras)
- load_settings(config_path)
+ load_settings(config_path, allow_extras=allow_extras)
if initializer is not None:
initializer({
View
34 logan/settings.py
@@ -12,10 +12,12 @@
import errno
import imp
import os
-from django.conf import settings
+from django.conf import settings as _settings
__all__ = ('create_default_settings', 'load_settings')
+TUPLE_SETTINGS = ('INSTALLED_APPS', 'TEMPLATE_DIRS')
+
def create_default_settings(filepath, settings_initializer):
if settings_initializer is not None:
@@ -31,7 +33,7 @@ def create_default_settings(filepath, settings_initializer):
fp.write(output)
-def load_settings(filename, silent=False):
+def load_settings(filename, silent=False, allow_extras=True, settings=_settings):
"""
Configures django settings from an arbitrary (non sys.path) filename.
"""
@@ -48,15 +50,35 @@ def load_settings(filename, silent=False):
if not settings.configured:
settings.configure()
- add_settings(mod)
+ add_settings(mod, allow_extras=allow_extras, settings=settings)
+
+def add_settings(mod, allow_extras=True, settings=_settings):
+ """
+ Adds all settings that are part of ``mod`` to the global settings object.
-def add_settings(mod):
- tuple_settings = ('INSTALLED_APPS', 'TEMPLATE_DIRS')
+ Special cases ``EXTRA_APPS`` to append the specified applications to the
+ list of ``INSTALLED_APPS``.
+ """
+ extras = {}
for setting in dir(mod):
if setting == setting.upper():
setting_value = getattr(mod, setting)
- if setting in tuple_settings and type(setting_value) == str:
+ if setting in TUPLE_SETTINGS and type(setting_value) == str:
setting_value = (setting_value,) # In case the user forgot the comma.
+
+ # Any setting that starts with EXTRA_ and matches a setting that is a list or tuple
+ # will automatically append the values to the current setting.
+ # It might make sense to make this less magical
+ if setting.startswith('EXTRA_'):
+ base_setting = setting.split('EXTRA_', 1)[-1]
+ if isinstance(getattr(settings, base_setting), (list, tuple)):
+ extras[base_setting] = setting_value
+ continue
+
setattr(settings, setting, setting_value)
+
+ for key, value in extras.iteritems():
+ curval = getattr(settings, key)
+ setattr(settings, key, curval + type(curval)(value))
View
1 setup.py
@@ -25,6 +25,7 @@
install_requires=[],
tests_require=[
'django>=1.2.5,<1.5',
+ 'mock>=0.8.0',
'nose>=1.1.2',
'unittest2',
],
View
58 tests/logan/settings/tests.py
@@ -1 +1,57 @@
-# TODO
+from unittest2 import TestCase
+
+import mock
+from logan.settings import add_settings
+
+
+class AddSettingsTestCase(TestCase):
+ def test_does_add_settings(self):
+ class NewSettings(object):
+ FOO = 'bar'
+ BAR = 'baz'
+
+ settings = mock.Mock()
+ new_settings = NewSettings()
+ add_settings(new_settings, settings=settings)
+ self.assertEquals(getattr(settings, 'FOO', None), 'bar')
+ self.assertEquals(getattr(settings, 'BAR', None), 'baz')
+
+ def test_extra_settings_dont_get_set(self):
+ class NewSettings(object):
+ EXTRA_FOO = ('lulz',)
+
+ settings = mock.Mock()
+ settings.FOO = ('foo', 'bar')
+ new_settings = NewSettings()
+ add_settings(new_settings, settings=settings)
+ self.assertFalse(settings.EXTRA_FOO.called)
+
+ def test_extra_settings_work_on_tuple(self):
+ class NewSettings(object):
+ EXTRA_FOO = ('lulz',)
+
+ settings = mock.Mock()
+ settings.FOO = ('foo', 'bar')
+ new_settings = NewSettings()
+ add_settings(new_settings, settings=settings)
+ self.assertEquals(getattr(settings, 'FOO', None), ('foo', 'bar', 'lulz'))
+
+ def test_extra_settings_work_on_list(self):
+ class NewSettings(object):
+ EXTRA_FOO = ['lulz']
+
+ settings = mock.Mock()
+ settings.FOO = ['foo', 'bar']
+ new_settings = NewSettings()
+ add_settings(new_settings, settings=settings)
+ self.assertEquals(getattr(settings, 'FOO', None), ['foo', 'bar', 'lulz'])
+
+ def test_extra_settings_work_on_mixed_iterables(self):
+ class NewSettings(object):
+ EXTRA_FOO = ('lulz',)
+
+ settings = mock.Mock()
+ settings.FOO = ['foo', 'bar']
+ new_settings = NewSettings()
+ add_settings(new_settings, settings=settings)
+ self.assertEquals(getattr(settings, 'FOO', None), ['foo', 'bar', 'lulz'])

0 comments on commit 4dda275

Please sign in to comment.
Something went wrong with that request. Please try again.