Permalink
Browse files

Initial version.

  • Loading branch information...
0 parents commit 775e1b9225c8e77e2beaae03eecf83ed6c03ebbd @jezdez jezdez committed Jul 21, 2012
@@ -0,0 +1,4 @@
+.coverage
+docs/_build
+*.egg-info
+test.db
@@ -0,0 +1,19 @@
+language: python
+python:
+ - "2.5"
+ - "2.6"
+ - "2.7"
+before_install:
+ - export PIP_USE_MIRRORS=true
+ - export PIP_INDEX_URL=https://simple.crate.io/
+install:
+ - pip install -e .
+ - pip install -r requirements/tests.txt Django==$DJANGO
+script:
+ - make test
+env:
+ - DJANGO=1.3.1
+ - DJANGO=1.4
+branches:
+ only:
+ - develop
@@ -0,0 +1,4 @@
+test:
+ flake8 configurations --ignore=E501,E127,E128,E124
+ coverage run --branch --source=configurations manage.py test configurations
+ coverage report --omit=configurations/test*
@@ -0,0 +1,75 @@
+django-configurations
+=====================
+
+.. image:: https://secure.travis-ci.org/jezdez/django-configurations.png
+ :alt: Build Status
+ :target: https://secure.travis-ci.org/jezdez/django-configurations
+
+django-configurations eases Django site configuration by relying
+on the composability of Python classes. It extends the notion of
+Django's module based settings loading with well established
+object oriented programming patterns.
+
+Quickstart
+----------
+
+Install django-configurations::
+
+ pip install django-configurations
+
+Then subclass the included ``configurations.Settings`` class in your
+project's ``settings.py`` or any other module you're using to store the
+settings constants, e.g.::
+
+ from configurations import Settings
+
+ class MySiteSettings(Settings):
+ DEBUG = True
+
+Set the ``DJANGO_CONFIGURATION`` environment variable to the name of the class
+you just created, e.g. in bash::
+
+ export DJANGO_CONFIGURATION=MySettings
+
+and the ``DJANGO_SETTINGS_MODULE`` environment variable to the module
+import path as usual, e.g. in bash::
+
+ export DJANGO_SETTINGS_MODULE=mysite.settings
+
+To enable Django to use your configuration you now have to modify your
+``manage.py`` or ``wsgi.py`` script to use django-configurations's versions
+of the appropriate starter functions, e.g. a typical ``manage.py`` using
+django-configurations would look like this::
+
+ #!/usr/bin/env python
+ import os
+ import sys
+
+ if __name__ == "__main__":
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
+ os.environ.setdefault('DJANGO_', 'MySettings')
+
+ from configurations.management import execute_from_command_line
+
+ execute_from_command_line(sys.argv)
+
+Notice in line 9 we don't use the common tool
+``django.core.management.execute_from_command_line`` but instead
+``configurations.management.execute_from_command_line``.
+
+The same applies to your ``wsgi.py`` file, e.g.::
+
+ import os
+
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
+ os.environ.setdefault('DJANGO_CONFIGURATION', 'MySettings')
+
+ from configurations.wsgi import get_wsgi_application
+
+ application = get_wsgi_application()
+
+Here we don't use the default ``django.core.wsgi.get_wsgi_application``
+function but instead ``configurations.wsgi.get_wsgi_application``.
+
+That's it! You can now use your project with ``manage.py`` and your favorite
+WSGI enabled server.
@@ -0,0 +1,5 @@
+# flake8: noqa
+from .base import Settings
+
+__version__ = '0.1a1'
+__all__ = ['Settings']
@@ -0,0 +1,60 @@
+from django.conf import global_settings
+from django.core.exceptions import ImproperlyConfigured
+
+from .utils import uppercase_attributes
+
+__all__ = ['Settings']
+
+
+install_failure = ("django-configurations settings importer wasn't "
+ "correctly installed. Please use one of the starter "
+ "functions to install it as mentioned in the docs: "
+ "http://django-configurations.readthedocs.org/")
+
+
+class SettingsBase(type):
+
+ def __new__(cls, name, bases, attrs):
+ if bases != (object,):
+ # if this is actually a subclass in a settings module
+ # we better check if the importer was correctly installed
+ from . import importer
+ if not importer.installed:
+ raise ImproperlyConfigured(install_failure)
+ settings_vars = uppercase_attributes(global_settings)
+ parents = [base for base in bases if isinstance(base, SettingsBase)]
+ if parents:
+ for base in bases[::-1]:
+ settings_vars.update(uppercase_attributes(base))
+ attrs = dict(settings_vars, **attrs)
+ return super(SettingsBase, cls).__new__(cls, name, bases, attrs)
+
+ def __repr__(self):
+ return "<Settings '%s.%s'>" % (self.__module__, self.__name__)
+
+
+class Settings(object):
+ """
+ The base configuration class to inherit from.
+
+ ::
+
+ class Develop(Settings):
+ EXTRA_AWESOME = True
+
+ @property
+ def SOMETHING(self):
+ return completely.different()
+
+ def OTHER(self):
+ if whatever:
+ return (1, 2, 3)
+ return (4, 5, 6)
+
+ The module this configuration class is located in will
+ automatically get the class and instance level attributes
+ with upper characters if the ``DJANGO_CONFIGURATION`` is set
+ to the name of the class.
+
+ """
+ __metaclass__ = SettingsBase
@@ -0,0 +1,75 @@
+import imp
+import os
+import sys
+
+from django.core.exceptions import ImproperlyConfigured
+from django.conf import ENVIRONMENT_VARIABLE
+
+from .utils import uppercase_attributes
+
+
+installed = False
+
+
+def install():
+ global installed
+ if not installed:
+ sys.meta_path.append(SettingsImporter())
+ installed = True
+
+
+class SettingsImporter(object):
+ class_varname = 'DJANGO_CONFIGURATION'
+ error_msg = "Settings cannot be imported, environment variable %s is undefined."
+
+ def __init__(self):
+ self.validate()
+
+ def __repr__(self):
+ return "<SettingsImporter for '%s.%s'>" % (self.module, self.name)
+
+ @property
+ def module(self):
+ return os.environ.get(ENVIRONMENT_VARIABLE)
+
+ @property
+ def name(self):
+ return os.environ.get(self.class_varname)
+
+ def validate(self):
+ if self.name is None:
+ raise ImproperlyConfigured(self.error_msg % self.class_varname)
+ if self.module is None:
+ raise ImproperlyConfigured(self.error_msg % ENVIRONMENT_VARIABLE)
+
+ def find_module(self, fullname, path=None):
+ if fullname is not None and fullname == self.module:
+ module = fullname.rsplit('.', 1)[-1]
+ return SettingsLoader(self.name, imp.find_module(module, path))
+ return None
+
+
+class SettingsLoader(object):
+
+ def __init__(self, name, location):
+ self.name = name
+ self.location = location
+
+ def load_module(self, fullname):
+ if fullname in sys.modules:
+ mod = sys.modules[fullname] # pragma: no cover
+ else:
+ mod = imp.load_module(fullname, *self.location)
+ try:
+ cls = getattr(mod, self.name)
+ obj = cls()
+ except AttributeError: # pragma: no cover
+ raise ImproperlyConfigured("Couldn't find settings '%s' in "
+ "module '%s'" %
+ (self.name, mod.__package__))
+ for name, value in uppercase_attributes(obj).items():
+ if callable(value):
+ value = value()
+ setattr(mod, name, value)
+ setattr(mod, 'CONFIGURATION', '%s.%s' % (fullname, self.name))
+ return mod
@@ -0,0 +1,5 @@
+from . import importer
+
+importer.install()
+
+from django.core.management import execute_from_command_line # noqa
No changes.
No changes.
@@ -0,0 +1,9 @@
+from configurations import Settings
+
+
+def test_callback(request):
+ return {}
+
+
+class Base(Settings):
+ pass
@@ -0,0 +1,43 @@
+import os
+from configurations import Settings
+
+
+class Test(Settings):
+ SITE_ID = 1
+
+ DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
+ }
+ }
+
+ INSTALLED_APPS = [
+ 'django.contrib.sessions',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sites',
+ 'django.contrib.auth',
+ 'django.contrib.admin',
+ 'configurations.tests',
+ ]
+
+ ROOT_URLCONF = 'configurations.tests.urls'
+
+ TEST_RUNNER = 'discover_runner.DiscoverRunner'
+
+ TEST_SETTING = True
+
+ _SOMETHING = 'YEAH'
+
+ DEBUG = True
+
+ @property
+ def LALA(self):
+ return 1
+
+ def LALA2(self):
+ return 1
+
+ def TEMPLATE_CONTEXT_PROCESSORS(self):
+ return Settings.TEMPLATE_CONTEXT_PROCESSORS + (
+ 'configurations.tests.settings.base.test_callback',)
@@ -0,0 +1,8 @@
+from .main import Test
+
+
+class Inheritance(Test):
+
+ def TEMPLATE_CONTEXT_PROCESSORS(self):
+ return super(Inheritance, self).TEMPLATE_CONTEXT_PROCESSORS() + (
+ 'configurations.tests.settings.base.test_callback',)
@@ -0,0 +1,8 @@
+from .base import Base
+
+
+class Inheritance(Base):
+
+ def TEMPLATE_CONTEXT_PROCESSORS(self):
+ return super(Inheritance, self).TEMPLATE_CONTEXT_PROCESSORS + (
+ 'configurations.tests.settings.base.test_callback',)
@@ -0,0 +1,41 @@
+import os
+
+from django.test import TestCase
+
+from mock import patch
+
+
+class InheritanceTests(TestCase):
+
+ @patch.dict(os.environ, clear=True,
+ DJANGO_CONFIGURATION='Inheritance',
+ DJANGO_SETTINGS_MODULE='configurations.tests.settings.single_inheritance')
+ def test_inherited(self):
+ from configurations.tests.settings import single_inheritance
+ self.assertEquals(single_inheritance.TEMPLATE_CONTEXT_PROCESSORS, (
+ 'django.contrib.auth.context_processors.auth',
+ 'django.core.context_processors.debug',
+ 'django.core.context_processors.i18n',
+ 'django.core.context_processors.media',
+ 'django.core.context_processors.static',
+ 'django.core.context_processors.tz',
+ 'django.contrib.messages.context_processors.messages',
+ 'configurations.tests.settings.base.test_callback',
+ ))
+
+ @patch.dict(os.environ, clear=True,
+ DJANGO_CONFIGURATION='Inheritance',
+ DJANGO_SETTINGS_MODULE='configurations.tests.settings.multiple_inheritance')
+ def test_inherited2(self):
+ from configurations.tests.settings import multiple_inheritance
+ self.assertEquals(multiple_inheritance.TEMPLATE_CONTEXT_PROCESSORS, (
+ 'django.contrib.auth.context_processors.auth',
+ 'django.core.context_processors.debug',
+ 'django.core.context_processors.i18n',
+ 'django.core.context_processors.media',
+ 'django.core.context_processors.static',
+ 'django.core.context_processors.tz',
+ 'django.contrib.messages.context_processors.messages',
+ 'configurations.tests.settings.base.test_callback',
+ 'configurations.tests.settings.base.test_callback',
+ ))
Oops, something went wrong.

0 comments on commit 775e1b9

Please sign in to comment.