Skip to content

Commit

Permalink
Merge remote-tracking branch 'hiisi13/master'
Browse files Browse the repository at this point in the history
Signed-off-by: Jannis Leidel <jannis@leidel.info>
  • Loading branch information
jezdez committed Jan 6, 2015
2 parents 01e3f58 + e33eeeb commit 44476bd
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 2 deletions.
74 changes: 74 additions & 0 deletions configurations/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import inspect
import sys

from django.core.exceptions import ImproperlyConfigured
Expand Down Expand Up @@ -122,3 +123,76 @@ def _process_args(self, largs, rargs, values):
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)
14 changes: 12 additions & 2 deletions configurations/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
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):
Expand Down Expand Up @@ -140,10 +140,20 @@ def __init__(self, *args, **kwargs):
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))

Expand Down
15 changes: 15 additions & 0 deletions tests/test_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,21 @@ def test_database_url_value(self):
'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, {})
Expand Down

0 comments on commit 44476bd

Please sign in to comment.