Skip to content

Instantly share code, notes, and snippets.

@dcollien
Last active August 29, 2015 14:07
Show Gist options
  • Save dcollien/59b437b30b142bdad4dc to your computer and use it in GitHub Desktop.
Save dcollien/59b437b30b142bdad4dc to your computer and use it in GitHub Desktop.
Automatic Argument Conversion Decorator
import calendar
from datetime import datetime
import types
import json
from functools import wraps
def convert_arg(type_name, value):
converter = None
if not isinstance(type_name, basestring):
converter = type_name
type_name = type_name.__name__
if isinstance(value, basestring):
if type_name == 'list':
try:
value = json_decode(value)
except ValueError:
value = [value]
elif type_name == 'tuple':
value = (value,)
elif type_name == 'datetime':
try:
value = float(value)
except ValueError:
value = None
else:
value = datetime.fromtimestamp(value)
elif type_name == 'dict':
value = json.loads(value)
elif type_name == 'int':
value = int(value)
elif type_name == 'long':
value = long(value)
elif type_name == 'float':
value = float(value)
elif type_name == 'bool':
value = (value.lower() == 'true') or (value.lower() == 'yes') or (value.lower() == '1')
elif converter is not None:
value = converter(value)
elif isinstance(value, int) or isinstance(value, float):
if type_name == 'datetime':
value = datetime.fromtimestamp(float(value))
if value is not None and type(value).__name__ != type_name and not converter:
raise TypeError("Expecting <type '" + type_name + "'>")
return value
def arg_types(**params):
def _decorator(func):
if isinstance(func, staticmethod):
func = func.__func__
@wraps(func)
def _inner(*args, **kwargs):
argSpec = getargspec(func)
argNames = argSpec.args
numArgs = len(args)
newArgs = []
i = 0
for argName in argNames:
if i < numArgs:
value = args[i]
i += 1
else:
value = kwargs[argName]
if argName in params:
try:
value = convert_arg(params[argName], value)
except TypeError as err:
raise TypeError(func.__name__ + ": Argument '" + argName + "' given incorrect type. " + str(err))
except ValueError as err:
raise ValueError(func.__name__ + ": Cannot convert " + str(type(value).__name__) + " argument '" + argName + "' to " + str(params[argName]) + '. ' + str(err))
newArgs.append(value)
return func(*newArgs)
return _inner
return _decorator
def test_arg_types():
class Dummy(object):
def __init__(self, arg):
self.arg = arg
def __str__(self):
return self.arg
@arg_types(date=datetime, number=int, isAwesome=bool, dummy=Dummy, things='list', stuff=dict)
def testfunc(date, number, isAwesome, dummy=None, things=[], stuff={}):
assert type(date) == datetime
assert str(date) == '2014-09-08 15:46:49+00:00'
assert type(number) == int
assert number == 42
assert type(isAwesome) == bool and isAwesome
assert isinstance(dummy, Dummy) and str(dummy) == 'test'
assert things[0] == 'a thing'
assert stuff['foo'] == 'bar'
testfunc('1410191209', '42', 'true', 'test', stuff='{"foo": "bar"}', things='a thing')
testfunc(1410191209, 42, 'yes', 'test', stuff={"foo": "bar"}, things='["a thing", "of Things"]')
print 'All Tests Passed'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment