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