mirror of
https://github.com/jazzband/django-configurations.git
synced 2026-03-16 22:20:27 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
8287ab6f7f
20 changed files with 377 additions and 74 deletions
6
.coveragerc
Normal file
6
.coveragerc
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[run]
|
||||
source = configurations
|
||||
branch = 1
|
||||
|
||||
[report]
|
||||
omit = *tests*,*migrations*
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@ build/
|
|||
.tox/
|
||||
htmlcov/
|
||||
*.pyc
|
||||
dist/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
language: python
|
||||
env:
|
||||
- TOXENV=coverage-py27-dj16
|
||||
- TOXENV=flake8-py27
|
||||
- TOXENV=flake8-py33
|
||||
- TOXENV=py26-dj14
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
include README.rst
|
||||
include AUTHORS
|
||||
include .travis.yml
|
||||
include manage.py
|
||||
include tasks.py
|
||||
recursive-include tests *
|
||||
recursive-include docs *
|
||||
|
|
|
|||
|
|
@ -13,3 +13,14 @@ def load_ipython_extension(ipython):
|
|||
from . import importer
|
||||
|
||||
importer.install()
|
||||
|
||||
|
||||
def setup(app):
|
||||
"""
|
||||
The callback for Sphinx that acts as a Sphinx extension.
|
||||
|
||||
Add this to the ``extensions`` config variable in your ``conf.py``.
|
||||
"""
|
||||
from . import importer
|
||||
|
||||
importer.install()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import os
|
||||
import re
|
||||
import warnings
|
||||
|
||||
from django.utils import six
|
||||
|
|
@ -66,9 +68,53 @@ class Configuration(six.with_metaclass(ConfigurationBase)):
|
|||
to the name of the class.
|
||||
|
||||
"""
|
||||
DOTENV_LOADED = None
|
||||
|
||||
@classmethod
|
||||
def load_dotenv(cls):
|
||||
"""
|
||||
Pulled from Honcho code with minor updates, reads local default
|
||||
environment variables from a .env file located in the project root
|
||||
or provided directory.
|
||||
|
||||
http://www.wellfireinteractive.com/blog/easier-12-factor-django/
|
||||
https://gist.github.com/bennylope/2999704
|
||||
"""
|
||||
# check if the class has DOTENV set wether with a path or None
|
||||
dotenv = getattr(cls, 'DOTENV', None)
|
||||
|
||||
# if DOTENV is falsy we want to disable it
|
||||
if not dotenv:
|
||||
return
|
||||
|
||||
# now check if we can access the file since we know we really want to
|
||||
try:
|
||||
with open(dotenv, 'r') as f:
|
||||
content = f.read()
|
||||
except IOError as e:
|
||||
raise ImproperlyConfigured("Couldn't read .env file "
|
||||
"with the path {}. Error: "
|
||||
"{}".format(dotenv, e))
|
||||
else:
|
||||
for line in content.splitlines():
|
||||
m1 = re.match(r'\A([A-Za-z_0-9]+)=(.*)\Z', line)
|
||||
if not m1:
|
||||
continue
|
||||
key, val = m1.group(1), m1.group(2)
|
||||
m2 = re.match(r"\A'(.*)'\Z", val)
|
||||
if m2:
|
||||
val = m2.group(1)
|
||||
m3 = re.match(r'\A"(.*)"\Z', val)
|
||||
if m3:
|
||||
val = re.sub(r'\\(.)', r'\1', m3.group(1))
|
||||
os.environ.setdefault(key, val)
|
||||
|
||||
cls.DOTENV_LOADED = dotenv
|
||||
|
||||
@classmethod
|
||||
def pre_setup(cls):
|
||||
pass
|
||||
if cls.DOTENV_LOADED is None:
|
||||
cls.load_dotenv()
|
||||
|
||||
@classmethod
|
||||
def post_setup(cls):
|
||||
|
|
@ -88,4 +134,4 @@ class Settings(Configuration):
|
|||
# make sure to remove the handling of the Settings class above when deprecating
|
||||
warnings.warn("configurations.Settings was renamed to "
|
||||
"settings.Configuration and will be "
|
||||
"removed in 1.0", PendingDeprecationWarning)
|
||||
"removed in 1.0", DeprecationWarning)
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@ import sys
|
|||
from optparse import make_option
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.management import LaxOptionParser
|
||||
from django.conf import ENVIRONMENT_VARIABLE as SETTINGS_ENVIRONMENT_VARIABLE
|
||||
|
||||
from .utils import uppercase_attributes, reraise
|
||||
from .utils import uppercase_attributes, reraise, LaxOptionParser
|
||||
from .values import Value, setup_value
|
||||
|
||||
installed = False
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ from . import importer
|
|||
|
||||
importer.install(check_options=True)
|
||||
|
||||
from django.core.management import execute_from_command_line # noqa
|
||||
from django.core.management import (execute_from_command_line, # noqa
|
||||
call_command)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import inspect
|
||||
import sys
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
|
@ -60,3 +61,138 @@ def reraise(exc, prefix=None, suffix=None):
|
|||
suffix = '(' + suffix + ')'
|
||||
exc.args = ('{0} {1} {2}'.format(prefix, exc.args[0], suffix),) + args[1:]
|
||||
raise
|
||||
|
||||
try:
|
||||
from django.core.management import LaxOptionParser
|
||||
except ImportError:
|
||||
from optparse import OptionParser
|
||||
|
||||
class LaxOptionParser(OptionParser):
|
||||
"""
|
||||
An option parser that doesn't raise any errors on unknown options.
|
||||
|
||||
This is needed because the --settings and --pythonpath options affect
|
||||
the commands (and thus the options) that are available to the user.
|
||||
|
||||
Backported from Django 1.7.x
|
||||
|
||||
"""
|
||||
def error(self, msg):
|
||||
pass
|
||||
|
||||
def print_help(self):
|
||||
"""Output nothing.
|
||||
|
||||
The lax options are included in the normal option parser, so under
|
||||
normal usage, we don't need to print the lax options.
|
||||
"""
|
||||
pass
|
||||
|
||||
def print_lax_help(self):
|
||||
"""Output the basic options available to every command.
|
||||
|
||||
This just redirects to the default print_help() behavior.
|
||||
"""
|
||||
OptionParser.print_help(self)
|
||||
|
||||
def _process_args(self, largs, rargs, values):
|
||||
"""
|
||||
Overrides OptionParser._process_args to exclusively handle default
|
||||
options and ignore args and other options.
|
||||
|
||||
This overrides the behavior of the super class, which stop parsing
|
||||
at the first unrecognized option.
|
||||
"""
|
||||
while rargs:
|
||||
arg = rargs[0]
|
||||
try:
|
||||
if arg[0:2] == "--" and len(arg) > 2:
|
||||
# process a single long option (possibly with value(s))
|
||||
# the superclass code pops the arg off rargs
|
||||
self._process_long_opt(rargs, values)
|
||||
elif arg[:1] == "-" and len(arg) > 1:
|
||||
# process a cluster of short options (possibly with
|
||||
# value(s) for the last one only)
|
||||
# the superclass code pops the arg off rargs
|
||||
self._process_short_opts(rargs, values)
|
||||
else:
|
||||
# it's either a non-default option or an arg
|
||||
# either way, add it to the args list so we can keep
|
||||
# dealing with options
|
||||
del rargs[0]
|
||||
raise Exception
|
||||
except: # Needed because we might need to catch a SystemExit
|
||||
largs.append(arg)
|
||||
|
||||
|
||||
# Copied over from Sphinx
|
||||
if sys.version_info >= (3, 0):
|
||||
from functools import partial
|
||||
|
||||
def getargspec(func):
|
||||
"""Like inspect.getargspec but supports functools.partial as well."""
|
||||
if inspect.ismethod(func):
|
||||
func = func.__func__
|
||||
if type(func) is partial:
|
||||
orig_func = func.func
|
||||
argspec = getargspec(orig_func)
|
||||
args = list(argspec[0])
|
||||
defaults = list(argspec[3] or ())
|
||||
kwoargs = list(argspec[4])
|
||||
kwodefs = dict(argspec[5] or {})
|
||||
if func.args:
|
||||
args = args[len(func.args):]
|
||||
for arg in func.keywords or ():
|
||||
try:
|
||||
i = args.index(arg) - len(args)
|
||||
del args[i]
|
||||
try:
|
||||
del defaults[i]
|
||||
except IndexError:
|
||||
pass
|
||||
except ValueError: # must be a kwonly arg
|
||||
i = kwoargs.index(arg)
|
||||
del kwoargs[i]
|
||||
del kwodefs[arg]
|
||||
return inspect.FullArgSpec(args, argspec[1], argspec[2],
|
||||
tuple(defaults), kwoargs,
|
||||
kwodefs, argspec[6])
|
||||
while hasattr(func, '__wrapped__'):
|
||||
func = func.__wrapped__
|
||||
if not inspect.isfunction(func):
|
||||
raise TypeError('%r is not a Python function' % func)
|
||||
return inspect.getfullargspec(func)
|
||||
|
||||
else: # 2.6, 2.7
|
||||
from functools import partial
|
||||
|
||||
def getargspec(func):
|
||||
"""Like inspect.getargspec but supports functools.partial as well."""
|
||||
if inspect.ismethod(func):
|
||||
func = func.im_func
|
||||
parts = 0, ()
|
||||
if type(func) is partial:
|
||||
keywords = func.keywords
|
||||
if keywords is None:
|
||||
keywords = {}
|
||||
parts = len(func.args), keywords.keys()
|
||||
func = func.func
|
||||
if not inspect.isfunction(func):
|
||||
raise TypeError('%r is not a Python function' % func)
|
||||
args, varargs, varkw = inspect.getargs(func.func_code)
|
||||
func_defaults = func.func_defaults
|
||||
if func_defaults is None:
|
||||
func_defaults = []
|
||||
else:
|
||||
func_defaults = list(func_defaults)
|
||||
if parts[0]:
|
||||
args = args[parts[0]:]
|
||||
if parts[1]:
|
||||
for arg in parts[1]:
|
||||
i = args.index(arg) - len(args)
|
||||
del args[i]
|
||||
try:
|
||||
del func_defaults[i]
|
||||
except IndexError:
|
||||
pass
|
||||
return inspect.ArgSpec(args, varargs, varkw, func_defaults)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from django.core import validators
|
|||
from django.core.exceptions import ValidationError, ImproperlyConfigured
|
||||
from django.utils import six
|
||||
|
||||
from .utils import import_by_path
|
||||
from .utils import import_by_path, getargspec
|
||||
|
||||
|
||||
def setup_value(target, name, value):
|
||||
|
|
@ -44,7 +44,7 @@ class Value(object):
|
|||
def __new__(cls, *args, **kwargs):
|
||||
"""
|
||||
checks if the creation can end up directly in the final value.
|
||||
That is the case whenever environ = False or environ_name is given
|
||||
That is the case whenever environ = False or environ_name is given.
|
||||
"""
|
||||
instance = object.__new__(cls)
|
||||
instance.__init__(*args, **kwargs)
|
||||
|
|
@ -59,7 +59,7 @@ class Value(object):
|
|||
environ_prefix='DJANGO', *args, **kwargs):
|
||||
if 'late_binding' in kwargs:
|
||||
self.late_binding = kwargs.get('late_binding')
|
||||
if isinstance(default, Value) and default.default:
|
||||
if isinstance(default, Value) and default.default is not None:
|
||||
self.default = copy.copy(default.default)
|
||||
else:
|
||||
self.default = default
|
||||
|
|
@ -140,10 +140,20 @@ class CastingMixin(object):
|
|||
error = 'Cannot use caster of {0} ({1!r})'.format(self,
|
||||
self.caster)
|
||||
raise ValueError(error)
|
||||
try:
|
||||
arg_names = getargspec(self._caster)[0]
|
||||
self._params = dict((name, kwargs[name])
|
||||
for name in arg_names
|
||||
if name in kwargs)
|
||||
except TypeError:
|
||||
self._params = {}
|
||||
|
||||
def to_python(self, value):
|
||||
try:
|
||||
return self._caster(value)
|
||||
if self._params:
|
||||
return self._caster(value, **self._params)
|
||||
else:
|
||||
return self._caster(value)
|
||||
except self.exception:
|
||||
raise ValueError(self.message.format(value))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,25 @@
|
|||
Cookbook
|
||||
========
|
||||
|
||||
Calling a Django management command
|
||||
-----------------------------------
|
||||
|
||||
.. versionadded:: 0.9
|
||||
|
||||
If you want to call a Django management command programmatically, say
|
||||
from a script outside of your usual Django code, you can use the
|
||||
equivalent of Django's :func:`~django.core.management.call_command` function
|
||||
with django-configurations, too.
|
||||
|
||||
Simply import it from ``configurations.management`` instead:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 1
|
||||
|
||||
from configurations.management import call_command
|
||||
|
||||
call_command('dumpdata', exclude=['contenttypes', 'auth'])
|
||||
|
||||
Envdir
|
||||
------
|
||||
|
||||
|
|
@ -14,7 +33,9 @@ Imagine for example you want to set a few environment variables, all you
|
|||
have to do is to create a directory with files that have capitalized names
|
||||
and contain the values you want to set.
|
||||
|
||||
Example::
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ tree mysite_env/
|
||||
mysite_env/
|
||||
|
|
@ -30,7 +51,9 @@ Example::
|
|||
$
|
||||
|
||||
Then, to enable the ``mysite_env`` environment variables, simply use the
|
||||
``envdir`` command line tool as a prefix for your program, e.g.::
|
||||
``envdir`` command line tool as a prefix for your program, e.g.:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ envdir mysite_env python manage.py runserver
|
||||
|
||||
|
|
@ -51,13 +74,17 @@ using pip_ to install packages.
|
|||
Django 1.5.x
|
||||
^^^^^^^^^^^^
|
||||
|
||||
First install Django 1.5.x and django-configurations::
|
||||
First install Django 1.5.x and django-configurations:
|
||||
|
||||
pip install -r https://raw.github.com/jezdez/django-configurations/templates/1.5.x/requirements.txt
|
||||
.. code-block:: console
|
||||
|
||||
Then create your new Django project with the provided template::
|
||||
$ pip install -r https://raw.github.com/jezdez/django-configurations/templates/1.5.x/requirements.txt
|
||||
|
||||
django-admin.py startproject mysite -v2 --template https://github.com/jezdez/django-configurations/archive/templates/1.5.x.zip
|
||||
Then create your new Django project with the provided template:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ django-admin.py startproject mysite -v2 --template https://github.com/jezdez/django-configurations/archive/templates/1.5.x.zip
|
||||
|
||||
See the repository of the template for more information:
|
||||
|
||||
|
|
@ -66,13 +93,17 @@ See the repository of the template for more information:
|
|||
Django 1.6.x
|
||||
^^^^^^^^^^^^
|
||||
|
||||
First install Django 1.6.x and django-configurations::
|
||||
First install Django 1.6.x and django-configurations:
|
||||
|
||||
pip install -r https://raw.github.com/jezdez/django-configurations/templates/1.6.x/requirements.txt
|
||||
.. code-block:: console
|
||||
|
||||
Or Django 1.6::
|
||||
$ pip install -r https://raw.github.com/jezdez/django-configurations/templates/1.6.x/requirements.txt
|
||||
|
||||
django-admin.py startproject mysite -v2 --template https://github.com/jezdez/django-configurations/archive/templates/1.6.x.zip
|
||||
Or Django 1.6:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ django-admin.py startproject mysite -v2 --template https://github.com/jezdez/django-configurations/archive/templates/1.6.x.zip
|
||||
|
||||
Now you have a default Django 1.5.x or 1.6.x project in the ``mysite``
|
||||
directory that uses django-configurations.
|
||||
|
|
@ -90,7 +121,9 @@ Celery
|
|||
^^^^^
|
||||
|
||||
Given Celery's way to load Django settings in worker processes you should
|
||||
probably just add the following to the **beginning** of your settings module::
|
||||
probably just add the following to the **beginning** of your settings module:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from configurations import importer
|
||||
importer.install()
|
||||
|
|
@ -145,26 +178,32 @@ enable an extension in your IPython configuration. See the IPython
|
|||
documentation for how to create and `manage your IPython profile`_ correctly.
|
||||
|
||||
Here's a quick how-to in case you don't have a profile yet. Type in your
|
||||
command line shell::
|
||||
command line shell:
|
||||
|
||||
ipython profile create
|
||||
.. code-block:: console
|
||||
|
||||
$ ipython profile create
|
||||
|
||||
Then let IPython show you where the configuration file ``ipython_config.py``
|
||||
was created::
|
||||
was created:
|
||||
|
||||
ipython locate profile
|
||||
.. code-block:: console
|
||||
|
||||
$ ipython locate profile
|
||||
|
||||
That should print a directory path where you can find the
|
||||
``ipython_config.py`` configuration file. Now open that file and extend the
|
||||
``c.InteractiveShellApp.extensions`` configuration value. It may be commented
|
||||
out from when IPython created the file or it may not exist in the file at all.
|
||||
In either case make sure it's not a Python comment anymore and reads like this::
|
||||
In either case make sure it's not a Python comment anymore and reads like this:
|
||||
|
||||
# A list of dotted module names of IPython extensions to load.
|
||||
c.InteractiveShellApp.extensions = [
|
||||
# .. your other extensions if available
|
||||
'configurations',
|
||||
]
|
||||
.. code-block:: python
|
||||
|
||||
# A list of dotted module names of IPython extensions to load.
|
||||
c.InteractiveShellApp.extensions = [
|
||||
# .. your other extensions if available
|
||||
'configurations',
|
||||
]
|
||||
|
||||
That will tell IPython to load django-configurations correctly on startup.
|
||||
It also works with django-extensions's shell_plus_ management command.
|
||||
|
|
@ -179,12 +218,14 @@ FastCGI
|
|||
In case you use FastCGI for deploying Django (you really shouldn't) and aren't
|
||||
allowed to use Django's runfcgi_ management command (that would automatically
|
||||
handle the setup for your if you've followed the quickstart guide above), make
|
||||
sure to use something like the following script::
|
||||
sure to use something like the following script:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
|
||||
os.environ.setdefault('DJANGO_CONFIGURATION', 'MySiteConfiguration')
|
||||
|
||||
|
|
@ -196,3 +237,33 @@ As you can see django-configurations provides a helper module
|
|||
``configurations.fastcgi`` that handles the setup of your configurations.
|
||||
|
||||
.. _runfcgi: https://docs.djangoproject.com/en/1.5/howto/deployment/fastcgi/
|
||||
|
||||
|
||||
Sphinx
|
||||
------
|
||||
|
||||
.. versionadded: 0.9
|
||||
|
||||
In case you would like to user the amazing `autodoc` feature of the
|
||||
documentation tool `Sphinx <http://sphinx-doc.org/>`_, you need add
|
||||
django-configurations to your ``extensions`` config variable and set
|
||||
the environment variable accordingly:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 2-3, 12
|
||||
|
||||
# My custom Django environment variables
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
|
||||
os.environ.setdefault('DJANGO_CONFIGURATION', 'Dev')
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.viewcode',
|
||||
# ...
|
||||
'configurations',
|
||||
]
|
||||
|
||||
# ...
|
||||
11
manage.py
11
manage.py
|
|
@ -1,11 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tests.settings.main')
|
||||
os.environ.setdefault('DJANGO_CONFIGURATION', 'Test')
|
||||
|
||||
from configurations.management import execute_from_command_line
|
||||
|
||||
execute_from_command_line(sys.argv)
|
||||
|
|
@ -1,2 +1,11 @@
|
|||
[pytest]
|
||||
django_find_project = false
|
||||
addopts = --cov configurations
|
||||
DJANGO_SETTINGS_MODULE = tests.settings.main
|
||||
DJANGO_CONFIGURATION = Test
|
||||
|
||||
[wheel]
|
||||
universal = 1
|
||||
|
||||
[flake8]
|
||||
ignore = E124,E501,E127,E128
|
||||
|
|
|
|||
1
test_project/.env
Normal file
1
test_project/.env
Normal file
|
|
@ -0,0 +1 @@
|
|||
DJANGO_DOTENV_VALUE='is set'
|
||||
|
|
@ -160,20 +160,6 @@ class Base(Configuration):
|
|||
}
|
||||
}
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
# Uncomment the next line to enable the admin:
|
||||
# 'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
# 'django.contrib.admindocs',
|
||||
'configurations',
|
||||
)
|
||||
|
||||
|
||||
class Debug(Base):
|
||||
YEAH = True
|
||||
|
|
|
|||
8
tests/settings/dot_env.py
Normal file
8
tests/settings/dot_env.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
from configurations import Configuration, values
|
||||
|
||||
|
||||
class DotEnvConfiguration(Configuration):
|
||||
|
||||
DOTENV = 'test_project/.env'
|
||||
|
||||
DOTENV_VALUE = values.Value()
|
||||
|
|
@ -3,9 +3,13 @@ import uuid
|
|||
import django
|
||||
|
||||
from configurations import Configuration, pristinemethod
|
||||
from configurations.values import BooleanValue
|
||||
|
||||
|
||||
class Test(Configuration):
|
||||
|
||||
ENV_LOADED = BooleanValue(False)
|
||||
|
||||
DEBUG = True
|
||||
|
||||
SITE_ID = 1
|
||||
|
|
@ -30,9 +34,6 @@ class Test(Configuration):
|
|||
|
||||
ROOT_URLCONF = 'tests.urls'
|
||||
|
||||
if django.VERSION[:2] < (1, 6):
|
||||
TEST_RUNNER = 'discover_runner.DiscoverRunner'
|
||||
|
||||
def TEMPLATE_CONTEXT_PROCESSORS(self):
|
||||
return Configuration.TEMPLATE_CONTEXT_PROCESSORS + (
|
||||
'tests.settings.base.test_callback',
|
||||
|
|
|
|||
14
tests/test_env.py
Normal file
14
tests/test_env.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import os
|
||||
from django.test import TestCase
|
||||
from mock import patch
|
||||
|
||||
|
||||
class DotEnvLoadingTests(TestCase):
|
||||
|
||||
@patch.dict(os.environ, clear=True,
|
||||
DJANGO_CONFIGURATION='DotEnvConfiguration',
|
||||
DJANGO_SETTINGS_MODULE='tests.settings.dot_env')
|
||||
def test_env_loaded(self):
|
||||
from tests.settings import dot_env
|
||||
self.assertEqual(dot_env.DOTENV_VALUE, 'is set')
|
||||
self.assertEqual(dot_env.DOTENV_LOADED, dot_env.DOTENV)
|
||||
|
|
@ -109,6 +109,12 @@ class ValueTests(TestCase):
|
|||
with env(DJANGO_TEST='nonboolean'):
|
||||
self.assertRaises(ValueError, value.setup, 'TEST')
|
||||
|
||||
def test_boolean_values_assign_false_to_another_booleanvalue(self):
|
||||
value1 = BooleanValue(False)
|
||||
value2 = BooleanValue(value1)
|
||||
self.assertFalse(value1.setup('TEST1'))
|
||||
self.assertFalse(value2.setup('TEST2'))
|
||||
|
||||
def test_integer_values(self):
|
||||
value = IntegerValue(1)
|
||||
with env(DJANGO_TEST='2'):
|
||||
|
|
@ -352,6 +358,21 @@ class ValueTests(TestCase):
|
|||
'USER': '',
|
||||
}})
|
||||
|
||||
def test_database_url_additional_args(self):
|
||||
|
||||
def mock_database_url_caster(self, url, engine=None):
|
||||
return { 'URL': url, 'ENGINE': engine }
|
||||
|
||||
with patch('configurations.values.DatabaseURLValue.caster', mock_database_url_caster):
|
||||
value = DatabaseURLValue(engine='django_mysqlpool.backends.mysqlpool')
|
||||
with env(DATABASE_URL='sqlite://'):
|
||||
self.assertEqual(value.setup('DATABASE_URL'), {
|
||||
'default': {
|
||||
'URL': 'sqlite://',
|
||||
'ENGINE': 'django_mysqlpool.backends.mysqlpool'
|
||||
}
|
||||
})
|
||||
|
||||
def test_email_url_value(self):
|
||||
value = EmailURLValue()
|
||||
self.assertEqual(value.default, {})
|
||||
|
|
|
|||
19
tox.ini
19
tox.ini
|
|
@ -20,32 +20,27 @@ basepython =
|
|||
pypy: pypy
|
||||
usedevelop = true
|
||||
deps =
|
||||
django-discover-runner
|
||||
mock
|
||||
dj-database-url
|
||||
dj-email-url
|
||||
dj-search-url
|
||||
django-cache-url>=0.6.0
|
||||
six
|
||||
https://github.com/pytest-dev/pytest-django/archive/master.zip#egg=pytest-django
|
||||
pytest-cov
|
||||
dj14: https://github.com/django/django/archive/stable/1.4.x.zip#egg=django
|
||||
dj15: https://github.com/django/django/archive/stable/1.5.x.zip#egg=django
|
||||
dj16: https://github.com/django/django/archive/stable/1.6.x.zip#egg=django
|
||||
dj17: https://github.com/django/django/archive/stable/1.7.x.zip#egg=django
|
||||
dj18: https://github.com/django/django/archive/master.zip#egg=django
|
||||
flake8: flake8
|
||||
coverage: coverage
|
||||
|
||||
commands =
|
||||
python manage.py test -v2 {posargs:tests} --failfast
|
||||
py.test {posargs:}
|
||||
|
||||
[testenv:flake8-py27]
|
||||
commands = flake8 configurations --ignore=E501,E127,E128,E124
|
||||
commands = flake8 configurations
|
||||
deps = flake8
|
||||
|
||||
[testenv:flake8-py33]
|
||||
commands = flake8 configurations --ignore=E501,E127,E128,E124
|
||||
|
||||
[testenv:coverage-py27-dj16]
|
||||
commands = coverage erase
|
||||
coverage run --source=. manage.py test -v2 {posargs:tests}
|
||||
coverage report -m configurations/*py
|
||||
coverage html configurations/*py
|
||||
commands = flake8 configurations
|
||||
deps = flake8
|
||||
|
|
|
|||
Loading…
Reference in a new issue