Created
July 4, 2011 08:17
-
-
Save reacocard/1063050 to your computer and use it in GitHub Desktop.
python decorator to make functions act statically typed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function = type(lambda x: x) | |
def __listcheck(typ, arg): | |
for i,x in enumerate(arg): | |
if not any((_typecheck(t, x) for t in typ)): | |
raise TypeError, "List member %s, \"%s\" is not of type %s!"%(i,x,typ) | |
return True | |
def __tuplecheck(typ, arg): | |
if len(typ) != len(arg): | |
raise TypeError, "Tuple length did not match." | |
for t,a,i in zip(typ, arg, range(len(typ))): | |
if not _typecheck(t, a): | |
raise TypeError, "Tuple member %s, \"%s\" is not of type %s!"%(i,a,t) | |
return True | |
def __setcheck(typ, arg): | |
for x in arg: | |
if not any((_typecheck(t, x) for t in typ)): | |
raise TypeError, "Set member \"%s\" is not of type %s!"%(x, typ) | |
return True | |
def __frozensetcheck(typ, arg): | |
for x in arg: | |
if not any((_typecheck(t, x) for t in typ)): | |
raise TypeError, "Frozenset member \"%s\" is not of type %s!"%(x, typ) | |
return True | |
def __dictcheck(typ, arg): | |
for k,v in arg.iteritems(): | |
for ktyp, vtyp in typ.iteritems(): | |
if _typecheck(ktyp, k) and _typecheck(vtyp, v): | |
break | |
else: | |
raise TypeError, "Dictionary member \"%s:%s\" is not of type %s!" % (k,v,typ) | |
return True | |
_deepchecks = { | |
list: __listcheck, | |
tuple: __tuplecheck, | |
set: __setcheck, | |
frozenset: __frozensetcheck, | |
dict: __dictcheck, | |
} | |
def _typecheck(typ, arg): | |
if isinstance(typ, type): | |
if not isinstance(arg, typ): | |
return False | |
elif isinstance(typ, function) and not typ(arg): | |
return False | |
elif not isinstance(arg, type(typ)): | |
return False | |
if type(arg) in _deepchecks: | |
if not _deepchecks[type(arg)](typ, arg): | |
return False | |
return True | |
def typed(*types, **kwtypes): | |
def outerwrapper(func): | |
def wrapper(*args, **kwargs): | |
if len(args) != len(types): | |
raise TypeError, "Incorrect argument count." | |
for typ, arg in zip(types, args): | |
if not _typecheck(typ, arg): | |
raise TypeError, "Argument %s failed typecheck." % (arg) | |
for kw, arg in kwargs.iteritems(): | |
vtype = kwtypes.get(kw, None) | |
if vtype is None: | |
raise TypeError, "Encountered unexpected keyword argumement %s."%kw | |
_typecheck(vtype, arg) | |
return func(*args, **kwargs) | |
return wrapper | |
return outerwrapper | |
@typed(lambda x: x) | |
def identity(x): | |
print x | |
@typed([int]) | |
def test(x): | |
print x | |
@typed((int, str)) | |
def tupletest(tup): | |
print tup | |
@typed({int: int}) | |
def intmap(d): | |
print d | |
@typed(int, a=str, b=int) | |
def opt(i, a=None, b=None): | |
print i, a, b |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment