Changed the default of the Value's environ option to True.

This commit is contained in:
Jannis Leidel 2013-09-03 12:03:34 +02:00
parent 5f4229057d
commit 927c052be5
4 changed files with 88 additions and 61 deletions

View file

@ -30,22 +30,22 @@ class FailingCasterValue(CastingMixin, Value):
class ValueTests(TestCase):
def test_value(self):
value = Value('default')
value = Value('default', environ=False)
self.assertEqual(value.setup('TEST'), 'default')
with env(DJANGO_TEST='override'):
self.assertEqual(value.setup('TEST'), 'default')
@patch.dict(os.environ, clear=True, DJANGO_TEST='override')
def test_env_var(self):
value = Value('default', environ=True)
value = Value('default')
self.assertEqual(value.setup('TEST'), 'override')
self.assertNotEqual(value.setup('TEST'), value.default)
self.assertEqual(value.to_python(os.environ['DJANGO_TEST']),
value.setup('TEST'))
def test_value_reuse(self):
value1 = Value('default', environ=True)
value2 = Value(value1, environ=True)
value1 = Value('default')
value2 = Value(value1)
self.assertEqual(value1.setup('TEST1'), 'default')
self.assertEqual(value2.setup('TEST2'), 'default')
with env(DJANGO_TEST1='override1', DJANGO_TEST2='override2'):
@ -54,15 +54,15 @@ class ValueTests(TestCase):
def test_env_var_prefix(self):
with patch.dict(os.environ, clear=True, ACME_TEST='override'):
value = Value('default', environ=True, environ_prefix='ACME')
value = Value('default', environ_prefix='ACME')
self.assertEqual(value.setup('TEST'), 'override')
with patch.dict(os.environ, clear=True, TEST='override'):
value = Value('default', environ=True, environ_prefix='')
value = Value('default', environ_prefix='')
self.assertEqual(value.setup('TEST'), 'override')
def test_boolean_values_true(self):
value = BooleanValue(False, environ=True)
value = BooleanValue(False)
for truthy in value.true_values:
with env(DJANGO_TEST=truthy):
self.assertTrue(value.setup('TEST'))
@ -71,32 +71,32 @@ class ValueTests(TestCase):
self.assertRaises(ImproperlyConfigured, BooleanValue, 'false')
def test_boolean_values_false(self):
value = BooleanValue(True, environ=True)
value = BooleanValue(True)
for falsy in value.false_values:
with env(DJANGO_TEST=falsy):
self.assertFalse(value.setup('TEST'))
def test_boolean_values_nonboolean(self):
value = BooleanValue(True, environ=True)
value = BooleanValue(True)
with env(DJANGO_TEST='nonboolean'):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_integer_values(self):
value = IntegerValue(1, environ=True)
value = IntegerValue(1)
with env(DJANGO_TEST='2'):
self.assertEqual(value.setup('TEST'), 2)
with env(DJANGO_TEST='noninteger'):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_float_values(self):
value = FloatValue(1.0, environ=True)
value = FloatValue(1.0)
with env(DJANGO_TEST='2.0'):
self.assertEqual(value.setup('TEST'), 2.0)
with env(DJANGO_TEST='noninteger'):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_decimal_values(self):
value = DecimalValue(decimal.Decimal(1), environ=True)
value = DecimalValue(decimal.Decimal(1))
with env(DJANGO_TEST='2'):
self.assertEqual(value.setup('TEST'), decimal.Decimal(2))
with env(DJANGO_TEST='nondecimal'):
@ -106,7 +106,7 @@ class ValueTests(TestCase):
self.assertRaises(ImproperlyConfigured, FailingCasterValue)
def test_list_values_default(self):
value = ListValue(environ=True)
value = ListValue()
with env(DJANGO_TEST='2,2'):
self.assertEqual(value.setup('TEST'), ['2', '2'])
with env(DJANGO_TEST='2, 2 ,'):
@ -115,32 +115,32 @@ class ValueTests(TestCase):
self.assertEqual(value.setup('TEST'), [])
def test_list_values_separator(self):
value = ListValue(environ=True, separator=':')
value = ListValue(separator=':')
with env(DJANGO_TEST='/usr/bin:/usr/sbin:/usr/local/bin'):
self.assertEqual(value.setup('TEST'),
['/usr/bin', '/usr/sbin', '/usr/local/bin'])
def test_List_values_converter(self):
value = ListValue(environ=True, converter=int)
value = ListValue(converter=int)
with env(DJANGO_TEST='2,2'):
self.assertEqual(value.setup('TEST'), [2, 2])
value = ListValue(environ=True, converter=float)
value = ListValue(converter=float)
with env(DJANGO_TEST='2,2'):
self.assertEqual(value.setup('TEST'), [2.0, 2.0])
def test_list_values_custom_converter(self):
value = ListValue(environ=True, converter=lambda x: x * 2)
value = ListValue(converter=lambda x: x * 2)
with env(DJANGO_TEST='2,2'):
self.assertEqual(value.setup('TEST'), ['22', '22'])
def test_list_values_converter_exception(self):
value = ListValue(environ=True, converter=int)
value = ListValue(converter=int)
with env(DJANGO_TEST='2,b'):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_tuple_values_default(self):
value = TupleValue(environ=True)
value = TupleValue()
with env(DJANGO_TEST='2,2'):
self.assertEqual(value.setup('TEST'), ('2', '2'))
with env(DJANGO_TEST='2, 2 ,'):
@ -149,7 +149,7 @@ class ValueTests(TestCase):
self.assertEqual(value.setup('TEST'), ())
def test_set_values_default(self):
value = SetValue(environ=True)
value = SetValue()
with env(DJANGO_TEST='2,2'):
self.assertEqual(value.setup('TEST'), set(['2', '2']))
with env(DJANGO_TEST='2, 2 ,'):
@ -158,7 +158,7 @@ class ValueTests(TestCase):
self.assertEqual(value.setup('TEST'), set())
def test_dict_values_default(self):
value = DictValue(environ=True)
value = DictValue()
with env(DJANGO_TEST='{2: 2}'):
self.assertEqual(value.setup('TEST'), {2: 2})
expected = {2: 2, '3': '3', '4': [1, 2, 3]}
@ -176,21 +176,21 @@ class ValueTests(TestCase):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_email_values(self):
value = EmailValue('spam@eg.gs', environ=True)
value = EmailValue('spam@eg.gs')
with env(DJANGO_TEST='spam@sp.am'):
self.assertEqual(value.setup('TEST'), 'spam@sp.am')
with env(DJANGO_TEST='spam'):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_url_values(self):
value = URLValue('http://eggs.spam', environ=True)
value = URLValue('http://eggs.spam')
with env(DJANGO_TEST='http://spam.eggs'):
self.assertEqual(value.setup('TEST'), 'http://spam.eggs')
with env(DJANGO_TEST='httb://spam.eggs'):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_ip_values(self):
value = IPValue('0.0.0.0', environ=True)
value = IPValue('0.0.0.0')
with env(DJANGO_TEST='127.0.0.1'):
self.assertEqual(value.setup('TEST'), '127.0.0.1')
with env(DJANGO_TEST='::1'):
@ -199,14 +199,14 @@ class ValueTests(TestCase):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_regex_values(self):
value = RegexValue('000--000', environ=True, regex=r'\d+--\d+')
value = RegexValue('000--000', regex=r'\d+--\d+')
with env(DJANGO_TEST='123--456'):
self.assertEqual(value.setup('TEST'), '123--456')
with env(DJANGO_TEST='123456'):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_path_values_with_check(self):
value = PathValue(environ=True)
value = PathValue()
with env(DJANGO_TEST='/'):
self.assertEqual(value.setup('TEST'), '/')
with env(DJANGO_TEST='~/'):
@ -215,7 +215,7 @@ class ValueTests(TestCase):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_path_values_no_check(self):
value = PathValue(environ=True, check_exists=False)
value = PathValue(check_exists=False)
with env(DJANGO_TEST='/'):
self.assertEqual(value.setup('TEST'), '/')
with env(DJANGO_TEST='~/spam/eggs'):
@ -233,7 +233,7 @@ class ValueTests(TestCase):
self.assertEqual(value.setup('SECRET_KEY'), '123')
def test_database_url_value(self):
value = DatabaseURLValue(environ=True)
value = DatabaseURLValue()
self.assertEqual(value.default, {})
with env(DATABASE_URL='sqlite://'):
self.assertEqual(value.setup('DATABASE_URL'), {
@ -247,7 +247,7 @@ class ValueTests(TestCase):
}})
def test_email_url_value(self):
value = EmailURLValue(environ=True)
value = EmailURLValue()
self.assertEqual(value.default, {})
with env(EMAIL_URL='smtps://user@domain.com:password@smtp.example.com:587'):
self.assertEqual(value.setup('EMAIL_URL'), {
@ -271,7 +271,7 @@ class ValueTests(TestCase):
self.assertRaises(ImproperlyConfigured, value.setup, 'TEST')
def test_cache_url_value(self):
value = CacheURLValue(environ=True)
value = CacheURLValue()
self.assertEqual(value.default, {})
with env(CACHE_URL='redis://user@host:port/1'):
self.assertEqual(value.setup('CACHE_URL'), {

View file

@ -28,7 +28,7 @@ class Value(object):
"""
multiple = False
def __init__(self, default=None, environ=False, environ_name=None,
def __init__(self, default=None, environ=True, environ_name=None,
environ_prefix='DJANGO', *args, **kwargs):
if isinstance(default, Value):
self.default = copy.copy(default.default)

View file

@ -22,8 +22,8 @@ Here is an example (from a **settings.py**)::
DEBUG = values.BooleanValue(True)
As you can see all you have to do is to wrap your settings value in a call
to one of the included settings classes. When Django's process starts up
it will automatically make sure the passed in value validates correctly --
to one of the included values classes. When Django's process starts up
it will automatically make sure the passed-in value validates correctly --
in the above case checks if the value is really a boolean.
You can safely use other :class:`~Value` instances as the default setting
@ -47,39 +47,67 @@ settings system Django uses.
Luckily django-configurations' :class:`~Value` subclasses have the ability
to handle environment variables for the most common use cases.
For example, imagine you'd like to override the ``TEMPLATE_DEBUG`` setting
on your staging server to be able to debug a problem with your in-development
code. You're using a web server that passes the environment variables from
the shell it was started in to your Django WSGI process.
Default behavior
^^^^^^^^^^^^^^^^
First make sure you set the ``environ`` option of the :class:`~Value` instance
to ``True``::
For example, imagine you'd like to override the ``ROOT_URLCONF`` setting
on your staging server to be able to debug a problem with your in-development
code. You're also using a web server that passes the environment variables from
the shell it was started from into your Django WSGI process.
Each :class:`~Value` class instance has an ``environ`` option, that when set to
``True`` (default) django-configurations will look for an uppercase
environment variable named like the :class:`~Value` instance's name, prefixed
with ``DJANGO_``. So imagine the following example::
from configurations import values
# ..
TEMPLATE_DEBUG = values.BooleanValue(True, environ=True)
ROOT_URLCONF = values.Value('mysite.urls')
That will tell django-configurations to look for a environment variable
named ``DJANGO_TEMPLATE_DEBUG`` when deciding which value of the ``DEBUG``
setting to actually enable.
django-configurations will try to read the ``DJANGO_ROOT_URLCONF`` environment
variable when deciding which value the ``ROOT_URLCONF`` setting should have.
When you run your web server simply specify that environment variable
(e.g. in your init script)::
DJANGO_TEMPLATE_DEBUG=true gunicorn mysite.wsgi:application
DJANGO_ROOT_URLCONF=mysite.debugging_urls gunicorn mysite.wsgi:application
Since environment variables are string based the ``BooleanValue`` supports
a series of possible formats for a boolean value (``true``, ``yes``,
``y`` and ``1``, all in capital and lower case, and ``false``, ``no``,
``n`` and ``0`` of course). So for example this will work, too::
Disabling environment variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
DJANGO_TEMPLATE_DEBUG=no ./manage.py runserver
To disable django-configurations' automatic use of environment variables,
you can specify the ``environ`` parameter of the :class:`~Value` class.
For example this would disable it for the ``TIME_ZONE`` setting value::
TIME_ZONE = values.Value('UTC', environ=False)
Custom environment variable names
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To support legacy systems, integrate with other parts of your sofware stack or
simply better match your taste in naming public configuration variables,
django-configurations allows you to use the ``environ_name`` parameter of the
:class:`~Value` class to change the name of the environment variable it looks
for. For example this would enforce a specific environment variable name
instead of using the name of the :class:`~Value` instance.::
TIME_ZONE = values.Value('UTC', environ_name='MYSITE_TZ')
Custom environment variable prefixes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In case you just want to change the default environment variable name prefix
of ``DJANGO`` to something to your likening, use the ``environ_prefix``
parameter of the :class:`~Value` instance. Here it'll look for the
``MYSITE_TIME_ZONE`` environment variable (instead of ``DJANGO_TIME_ZONE``)::
TIME_ZONE = values.Value('UTC', environ_prefix='MYSITE')
``Value`` class
---------------
.. class:: Value(default, [environ=False, environ_name=None, environ_prefix='DJANGO'])
.. class:: Value(default, [environ=True, environ_name=None, environ_prefix='DJANGO'])
The ``Value`` class takes one required and several optional parameters.
@ -114,10 +142,10 @@ a series of possible formats for a boolean value (``true``, ``yes``,
environment
The ``to_python`` method is only used when the ``environ`` parameter
of the :class:`~Value` class is set to ``True`` and an environment
variable with the appropriate name was found. It will be used to handle
the string based environment variable values and returns the "ready"
value to be returned by the ``setup`` method.
of the :class:`~Value` class is set to ``True`` (the default) and an
environment variable with the appropriate name was found. It will be
used to handle the string based environment variable values and returns
the "ready" value to be returned by the ``setup`` method.
Built-ins
---------
@ -185,8 +213,7 @@ Type values
return person
MONTY_PYTHONS = ListValue(['John Cleese', 'Eric Idle'],
converter=check_monty_python,
environ=True)
converter=check_monty_python)
You can override this list with an environment variable like this::
@ -194,8 +221,7 @@ Type values
Use a custom separator::
EMERGENCY_EMAILS = ListValue(['admin@mysite.net'],
separator=';', environ=True)
EMERGENCY_EMAILS = ListValue(['admin@mysite.net'], separator=';')
And override it::
@ -253,7 +279,7 @@ Validator values
LOADBALANCER_IP = values.IPValue('127.0.0.1')
.. class:: RegexValue(default, regex, [environ=False, environ_name=None, environ_prefix='DJANGO'])
.. class:: RegexValue(default, regex, [environ=True, environ_name=None, environ_prefix='DJANGO'])
A :class:`~Value` subclass that validates according a regular expression
and uses the :class:`django:django.core.validators.RegexValidator`.
@ -264,7 +290,7 @@ Validator values
DEFAULT_SKU = values.RegexValue('000-000-00', regex=r'\d{3}-\d{3}-\d{2}')
.. class:: PathValue(default, [check_exists=True, environ=False, environ_name=None, environ_prefix='DJANGO'])
.. class:: PathValue(default, [check_exists=True, environ=True, environ_name=None, environ_prefix='DJANGO'])
A :class:`~Value` subclass that normalizes the given path using
:func:`os.path.expanduser` and validates if it exists on the file system.

View file

@ -3,7 +3,8 @@ import os
import sys
if __name__ == "__main__":
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'configurations.tests.settings.main')
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'configurations.tests.settings.main')
os.environ.setdefault('DJANGO_CONFIGURATION', 'Test')
from configurations.management import execute_from_command_line