Created
July 24, 2009 20:57
-
-
Save tav/154549 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| # Copyright (c) 2009 Metanational Commons Ltd. | |
| from time import time | |
| from sha import new as sha1 | |
| CO_VARARGS = 4 | |
| CO_VARKEYWORDS = 8 | |
| def validate(**spec): | |
| def __decorate(func): | |
| rkey = sha1(str(time())).hexdigest()[:8] | |
| rkw = 'kw_%s' % rkey | |
| code = func.func_code | |
| varnames = list(code.co_varnames) | |
| defaults = func.func_defaults or () | |
| varargs = varkwargs = None | |
| if code.co_flags & CO_VARKEYWORDS: | |
| varkwargs = varnames.pop(-1) | |
| if code.co_flags & CO_VARARGS: | |
| varargs = varnames.pop(-1) | |
| params = [varnames.pop(0)]; add = params.append | |
| params2 = params[:]; add2 = params2.append | |
| default_pointer = len(varnames) - len(defaults) | |
| for idx, varname in enumerate(varnames): | |
| if idx < default_pointer: | |
| add(varname) | |
| add2("%s[%r]" % (rkw, varname)) | |
| else: | |
| add("%s=defaults_%s[%s]" % (varname, rkey, idx-default_pointer)) | |
| add2("%s=%s.get(%r, defaults_%s[%s])" % (varname, rkw, varname, rkey, idx-default_pointer)) | |
| if varargs: | |
| add("*%s" % varargs) | |
| add2("*%s[%r]" % (rkw, varargs)) | |
| if varkwargs: | |
| add("**%s" % varkwargs) | |
| add2("**%s[%r]" % (rkw, varkwargs)) | |
| params = ", ".join(params) | |
| params2 = ", ".join(params2) | |
| source = """ | |
| def newfunc(%(params)s): | |
| kwargs_%(r)s = locals() | |
| kw_%(r)s = {} | |
| for key_%(r)s in kwargs_%(r)s: | |
| if key_%(r)s in spec_%(r)s: | |
| kw_%(r)s[key_%(r)s] = spec_%(r)s[key_%(r)s](kwargs_%(r)s[key_%(r)s]) | |
| else: | |
| kw_%(r)s[key_%(r)s] = kwargs_%(r)s[key_%(r)s] | |
| return func_%(r)s(%(params2)s) | |
| """ % dict(params=params, params2=params2, r=rkey) | |
| print source | |
| env = { | |
| 'func_%s' % rkey: func, | |
| 'spec_%s' % rkey: spec, | |
| 'defaults_%s' % rkey: defaults, | |
| } | |
| exec source in env | |
| return env['newfunc'] | |
| return __decorate | |
| @validate(a=float, b=str, c=int) | |
| def foo(ctx, a, b, c=3, d=4, **kwargs): | |
| print "a:", `a` | |
| print "b:", `b` | |
| print "c:", `c` | |
| print "d:", `d` | |
| print "kwargs:", `kwargs` | |
| def foo2(ctx, a, b, c=3, d=4, **kwargs): | |
| print "a:", `a` | |
| print "b:", `b` | |
| print "c:", `c` | |
| print "d:", `d` | |
| print "kwargs:", `kwargs` | |
| @validate(a=float, b=str) | |
| def bar(ctx, a, b, *args, **kwargs): | |
| print "a:", `a` | |
| print "b:", `b` | |
| print "args:", `args` | |
| print "kwargs:", `kwargs` | |
| @validate(a=float, b=str) | |
| def spam(ctx, a, b, *args): | |
| print "a:", `a` | |
| print "b:", `b` | |
| print "args:", `args` | |
| @validate(a=int, b=str) | |
| def blah(ctx, a, b): | |
| print "a:", `a` | |
| print "b:", `b` | |
| @validate(a=float, b=str, c=int) | |
| def yam(ctx, a, b, c=3, d=4, **kwargs): | |
| pass | |
| def validate2(**spec): | |
| def __decorate(func): | |
| def __decorated(*args, **kwargs): | |
| return func(*args, **kwargs) | |
| return __decorated | |
| return __decorate | |
| @validate2(a=float, b=str, c=int) | |
| def yam2(ctx, a, b, c=3, d=4, **kwargs): | |
| pass | |
| def yam3(ctx, a, b, c=3, d=4, **kwargs): | |
| pass | |
| foo(None, 20, 'hello', 4, 33, random='foo') | |
| bar(None, 20, 'hello', 4, 33, random='foo') | |
| spam(None, 20, 'hello', 4, 33, 'foo') | |
| blah(None, 20, 'hello') | |
| start = time() | |
| for i in xrange(10000): | |
| yam(None, 20, 'hello', 4, 33, random='foo') | |
| end = time() | |
| start2 = time() | |
| for i in xrange(10000): | |
| yam2(None, 20, 'hello', 4, 33, random='foo') | |
| end2 = time() | |
| start3 = time() | |
| for i in xrange(10000): | |
| yam3(None, 20, 'hello', 4, 33, random='foo') | |
| end3 = time() | |
| print "Native:", end3 - start3 | |
| print "Decorated:", end2 - start2 | |
| print "Validated:", end - start | |
| print "Multiplier:", (end - start) / (end2 - start2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment