Renamed Settings class to Configuration to better match what it means. Settings is still importable and is marked to be deprecated in 1.0.

This commit is contained in:
Jannis Leidel 2013-07-27 12:05:39 +02:00
parent aac7af881c
commit e31adbaeed
10 changed files with 79 additions and 66 deletions

View file

@ -19,7 +19,7 @@ Install django-configurations:
pip install django-configurations pip install django-configurations
Then subclass the included ``configurations.Settings`` class in your Then subclass the included ``configurations.Configuration`` class in your
project's **settings.py** or any other module you're using to store the project's **settings.py** or any other module you're using to store the
settings constants, e.g.: settings constants, e.g.:
@ -27,9 +27,9 @@ settings constants, e.g.:
# mysite/settings.py # mysite/settings.py
from configurations import Settings from configurations import Configuration
class Dev(Settings): class Dev(Configuration):
DEBUG = True DEBUG = True
Set the ``DJANGO_CONFIGURATION`` environment variable to the name of the class Set the ``DJANGO_CONFIGURATION`` environment variable to the name of the class

View file

@ -1,6 +1,6 @@
# flake8: noqa # flake8: noqa
from .base import Settings from .base import Settings, Configuration
from .decorators import pristinemethod from .decorators import pristinemethod
__version__ = '0.3' __version__ = '0.3'
__all__ = ['Settings', 'pristinemethod'] __all__ = ['Configuration', 'pristinemethod']

View file

@ -1,10 +1,12 @@
import six import warnings
from django.utils import six
from django.conf import global_settings from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from .utils import uppercase_attributes from .utils import uppercase_attributes
__all__ = ['Settings'] __all__ = ['Configuration']
install_failure = ("django-configurations settings importer wasn't " install_failure = ("django-configurations settings importer wasn't "
@ -13,7 +15,7 @@ install_failure = ("django-configurations settings importer wasn't "
"http://django-configurations.readthedocs.org/") "http://django-configurations.readthedocs.org/")
class SettingsBase(type): class ConfigurationBase(type):
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
if bases != (object,) and bases[0].__name__ != 'NewBase': if bases != (object,) and bases[0].__name__ != 'NewBase':
@ -23,24 +25,26 @@ class SettingsBase(type):
if not importer.installed: if not importer.installed:
raise ImproperlyConfigured(install_failure) raise ImproperlyConfigured(install_failure)
settings_vars = uppercase_attributes(global_settings) settings_vars = uppercase_attributes(global_settings)
parents = [base for base in bases if isinstance(base, SettingsBase)] parents = [base for base in bases if isinstance(base,
ConfigurationBase)]
if parents: if parents:
for base in bases[::-1]: for base in bases[::-1]:
settings_vars.update(uppercase_attributes(base)) settings_vars.update(uppercase_attributes(base))
attrs = dict(settings_vars, **attrs) attrs = dict(settings_vars, **attrs)
return super(SettingsBase, cls).__new__(cls, name, bases, attrs) return super(ConfigurationBase, cls).__new__(cls, name, bases, attrs)
def __repr__(self): def __repr__(self):
return "<Settings '%s.%s'>" % (self.__module__, self.__name__) return "<Configuration '{0}.{1}'>".format(self.__module__,
self.__name__)
class Settings(six.with_metaclass(SettingsBase)): class Configuration(six.with_metaclass(ConfigurationBase)):
""" """
The base configuration class to inherit from. The base configuration class to inherit from.
:: ::
class Develop(Settings): class Develop(Configuration):
EXTRA_AWESOME = True EXTRA_AWESOME = True
@property @property
@ -65,3 +69,12 @@ class Settings(six.with_metaclass(SettingsBase)):
@classmethod @classmethod
def post_setup(cls): def post_setup(cls):
pass pass
class Settings(Configuration):
@classmethod
def pre_setup(cls):
warnings.warn("configurations.Settings was renamed to "
"settings.Configuration and will be "
"removed in 1.0", PendingDeprecationWarning)

View file

@ -4,9 +4,9 @@ def pristinemethod(func):
Use it like this:: Use it like this::
from configurations import pristinemethod from configurations import Configuration, pristinemethod
class Develop(Settings): class Develop(Configuration):
@pristinemethod @pristinemethod
def USER_CHECK(user): def USER_CHECK(user):

View file

@ -30,8 +30,8 @@ class StdoutWrapper(object):
def write(self, msg, *args, **kwargs): def write(self, msg, *args, **kwargs):
if 'Django version' in msg: if 'Django version' in msg:
new_msg_part = (", configuration %r" % new_msg_part = (", configuration {!r}".format(
os.environ.get(CONFIGURATION_ENVIRONMENT_VARIABLE)) os.environ.get(CONFIGURATION_ENVIRONMENT_VARIABLE)))
msg_parts = msg.split('\n') msg_parts = msg.split('\n')
modified_msg_parts = [] modified_msg_parts = []
for msg_part in msg_parts: for msg_part in msg_parts:
@ -53,7 +53,7 @@ def patch_inner_run(original):
configuration_options = ( configuration_options = (
make_option('--configuration', make_option('--configuration',
help='The name of the settings class to load, e.g. ' help='The name of the configuration class to load, e.g. '
'"Development". If this isn\'t provided, the ' '"Development". If this isn\'t provided, the '
'DJANGO_CONFIGURATION environment variable will ' 'DJANGO_CONFIGURATION environment variable will '
'be used.'),) 'be used.'),)
@ -69,16 +69,16 @@ def install():
# add the configuration option to all management commands # add the configuration option to all management commands
base.BaseCommand.option_list += configuration_options base.BaseCommand.option_list += configuration_options
sys.meta_path.insert(0, SettingsImporter()) sys.meta_path.insert(0, ConfigurationImporter())
installed = True installed = True
# now patch the active runserver command to show a nicer output # now patch the active runserver command to show a nicer output
commands = management.get_commands() commands = management.get_commands()
runserver_path = commands.get('runserver', None) runserver = commands.get('runserver', None)
if runserver_path is not None: if runserver is not None:
full_path = '%s.management.commands.runserver' % runserver_path path = '{0}.management.commands.runserver'.format(runserver)
try: try:
runserver_module = import_module(full_path) runserver_module = import_module(path)
except ImportError: except ImportError:
pass pass
else: else:
@ -91,9 +91,9 @@ def handle_configurations_option(options):
os.environ[CONFIGURATION_ENVIRONMENT_VARIABLE] = options.configuration os.environ[CONFIGURATION_ENVIRONMENT_VARIABLE] = options.configuration
class SettingsImporter(object): class ConfigurationImporter(object):
error_msg = ("Settings cannot be imported, " error_msg = ("Configuration cannot be imported, "
"environment variable %s is undefined.") "environment variable {0} is undefined.")
def __init__(self): def __init__(self):
self.argv = sys.argv[:] self.argv = sys.argv[:]
@ -107,7 +107,8 @@ class SettingsImporter(object):
self.validate() self.validate()
def __repr__(self): def __repr__(self):
return "<SettingsImporter for '%s.%s'>" % (self.module, self.name) return "<ConfigurationImporter for '{0}.{1}'>".format(self.module,
self.name)
@property @property
def module(self): def module(self):
@ -119,16 +120,16 @@ class SettingsImporter(object):
def validate(self): def validate(self):
if self.name is None: if self.name is None:
raise ImproperlyConfigured(self.error_msg % raise ImproperlyConfigured(self.error_msg.format(
CONFIGURATION_ENVIRONMENT_VARIABLE) CONFIGURATION_ENVIRONMENT_VARIABLE))
if self.module is None: if self.module is None:
raise ImproperlyConfigured(self.error_msg % raise ImproperlyConfigured(self.error_msg.format(
SETTINGS_ENVIRONMENT_VARIABLE) SETTINGS_ENVIRONMENT_VARIABLE))
def find_module(self, fullname, path=None): def find_module(self, fullname, path=None):
if fullname is not None and fullname == self.module: if fullname is not None and fullname == self.module:
module = fullname.rsplit('.', 1)[-1] module = fullname.rsplit('.', 1)[-1]
return SettingsLoader(self.name, imp.find_module(module, path)) return ConfigurationLoader(self.name, imp.find_module(module, path))
return None return None
@ -148,7 +149,7 @@ def reraise(exc, prefix=None, suffix=None):
raise raise
class SettingsLoader(object): class ConfigurationLoader(object):
def __init__(self, name, location): def __init__(self, name, location):
self.name = name self.name = name
@ -159,46 +160,45 @@ class SettingsLoader(object):
mod = sys.modules[fullname] # pragma: no cover mod = sys.modules[fullname] # pragma: no cover
else: else:
mod = imp.load_module(fullname, *self.location) mod = imp.load_module(fullname, *self.location)
cls_path = '%s.%s' % (mod.__name__, self.name) cls_path = '{0}.{1}'.format(mod.__name__, self.name)
try: try:
cls = getattr(mod, self.name) cls = getattr(mod, self.name)
except AttributeError as err: # pragma: no cover except AttributeError as err: # pragma: no cover
reraise(err, reraise(err, "While trying to find the '{0}' "
"While trying to find the '%s' settings in module '%s'" % "settings in module '{1}'".format(self.name,
(self.name, mod.__package__)) mod.__package__))
try: try:
cls.pre_setup() cls.pre_setup()
except Exception as err: except Exception as err:
reraise(err, "While calling '%s.pre_setup()'" % cls_path) reraise(err, "While calling '{0}.pre_setup()'".format(cls_path))
try: try:
obj = cls() obj = cls()
except Exception as err: except Exception as err:
reraise(err, reraise(err, "While initializing the '{0}' "
"While loading the '%s' settings" % cls_path) "configuration".format(cls_path))
try: try:
attributes = uppercase_attributes(obj).items() attributes = uppercase_attributes(obj).items()
except Exception as err: except Exception as err:
reraise(err, reraise(err, "While getting the items "
"While getting the items of the '%s' settings" % "of the '{0}' configuration".format(cls_path))
cls_path)
for name, value in attributes: for name, value in attributes:
if callable(value) and not getattr(value, 'pristine', False): if callable(value) and not getattr(value, 'pristine', False):
try: try:
value = value() value = value()
except Exception as err: except Exception as err:
reraise(err, reraise(err, "While calling '{0}.{1}'".format(cls_path,
"While calling '%s.%s'" % (cls_path, value)) value))
setattr(mod, name, value) setattr(mod, name, value)
setattr(mod, 'CONFIGURATION', '%s.%s' % (fullname, self.name)) setattr(mod, 'CONFIGURATION', '{0}.{1}'.format(fullname, self.name))
try: try:
cls.post_setup() cls.post_setup()
except Exception as err: except Exception as err:
reraise(err, "While calling '%s.post_setup()'" % cls_path) reraise(err, "While calling '{0}.post_setup()'".format(cls_path))
return mod return mod

View file

@ -1,9 +1,9 @@
from configurations import Settings from configurations import Configuration
def test_callback(request): def test_callback(request):
return {} return {}
class Base(Settings): class Base(Configuration):
pass pass

View file

@ -1,9 +1,9 @@
import os import os
import uuid import uuid
from configurations import Settings, pristinemethod from configurations import Configuration, pristinemethod
class Test(Settings): class Test(Configuration):
DEBUG = True DEBUG = True
SITE_ID = 1 SITE_ID = 1
@ -31,7 +31,7 @@ class Test(Settings):
TEST_RUNNER = 'discover_runner.DiscoverRunner' TEST_RUNNER = 'discover_runner.DiscoverRunner'
def TEMPLATE_CONTEXT_PROCESSORS(self): def TEMPLATE_CONTEXT_PROCESSORS(self):
return Settings.TEMPLATE_CONTEXT_PROCESSORS + ( return Configuration.TEMPLATE_CONTEXT_PROCESSORS + (
'configurations.tests.settings.base.test_callback',) 'configurations.tests.settings.base.test_callback',)
ATTRIBUTE_SETTING = True ATTRIBUTE_SETTING = True

View file

@ -1,4 +1,4 @@
from configurations import Settings from configurations import Configuration
class Mixin1(object): class Mixin1(object):
@ -17,7 +17,7 @@ class Mixin2(object):
'some_app.context_processors.processor2',) 'some_app.context_processors.processor2',)
class Inheritance(Mixin2, Mixin1, Settings): class Inheritance(Mixin2, Mixin1, Configuration):
@property @property
def TEMPLATE_CONTEXT_PROCESSORS(self): def TEMPLATE_CONTEXT_PROCESSORS(self):

View file

@ -6,7 +6,7 @@ from django.core.exceptions import ImproperlyConfigured
from mock import patch from mock import patch
from configurations.importer import SettingsImporter from configurations.importer import ConfigurationImporter
class MainTests(TestCase): class MainTests(TestCase):
@ -41,39 +41,39 @@ class MainTests(TestCase):
@patch.dict(os.environ, clear=True, DJANGO_CONFIGURATION='Test') @patch.dict(os.environ, clear=True, DJANGO_CONFIGURATION='Test')
def test_empty_module_var(self): def test_empty_module_var(self):
self.assertRaises(ImproperlyConfigured, SettingsImporter) self.assertRaises(ImproperlyConfigured, ConfigurationImporter)
@patch.dict(os.environ, clear=True, @patch.dict(os.environ, clear=True,
DJANGO_SETTINGS_MODULE='configurations.tests.settings.main') DJANGO_SETTINGS_MODULE='configurations.tests.settings.main')
def test_empty_class_var(self): def test_empty_class_var(self):
self.assertRaises(ImproperlyConfigured, SettingsImporter) self.assertRaises(ImproperlyConfigured, ConfigurationImporter)
def test_global_settings(self): def test_global_settings(self):
from configurations.base import Settings from configurations.base import Configuration
self.assertEqual(Settings.LOGGING_CONFIG, 'django.utils.log.dictConfig') self.assertEqual(Configuration.LOGGING_CONFIG, 'django.utils.log.dictConfig')
self.assertEqual(repr(Settings), self.assertEqual(repr(Configuration),
"<Settings 'configurations.base.Settings'>") "<Configuration 'configurations.base.Configuration'>")
def test_repr(self): def test_repr(self):
from configurations.tests.settings.main import Test from configurations.tests.settings.main import Test
self.assertEqual(repr(Test), self.assertEqual(repr(Test),
"<Settings 'configurations.tests.settings.main.Test'>") "<Configuration 'configurations.tests.settings.main.Test'>")
@patch.dict(os.environ, clear=True, @patch.dict(os.environ, clear=True,
DJANGO_SETTINGS_MODULE='configurations.tests.settings.main', DJANGO_SETTINGS_MODULE='configurations.tests.settings.main',
DJANGO_CONFIGURATION='Test') DJANGO_CONFIGURATION='Test')
def test_initialization(self): def test_initialization(self):
importer = SettingsImporter() importer = ConfigurationImporter()
self.assertEqual(importer.module, 'configurations.tests.settings.main') self.assertEqual(importer.module, 'configurations.tests.settings.main')
self.assertEqual(importer.name, 'Test') self.assertEqual(importer.name, 'Test')
self.assertEqual(repr(importer), self.assertEqual(repr(importer),
"<SettingsImporter for 'configurations.tests.settings.main.Test'>") "<ConfigurationImporter for 'configurations.tests.settings.main.Test'>")
@patch.dict(os.environ, clear=True, @patch.dict(os.environ, clear=True,
DJANGO_SETTINGS_MODULE='configurations.tests.settings.inheritance', DJANGO_SETTINGS_MODULE='configurations.tests.settings.inheritance',
DJANGO_CONFIGURATION='Inheritance') DJANGO_CONFIGURATION='Inheritance')
def test_initialization_inheritance(self): def test_initialization_inheritance(self):
importer = SettingsImporter() importer = ConfigurationImporter()
self.assertEqual(importer.module, self.assertEqual(importer.module,
'configurations.tests.settings.inheritance') 'configurations.tests.settings.inheritance')
self.assertEqual(importer.name, 'Inheritance') self.assertEqual(importer.name, 'Inheritance')

View file

@ -20,7 +20,7 @@ use of the ``from foo import *`` anti-pattern.
Okay, how does it work? Okay, how does it work?
----------------------- -----------------------
Any subclass of the ``configurations.Settings`` class will automatically Any subclass of the ``configurations.Configuration`` class will automatically
use the values of its class and instance attributes (including properties use the values of its class and instance attributes (including properties
and methods) to set module level variables of the same module -- that's and methods) to set module level variables of the same module -- that's
how Django will interface to the django-configurations based settings during how Django will interface to the django-configurations based settings during