def _build_descriptor(rule=None, __frame=None, __name=None, __proptype=CellAttribute.mkattr, __ruleattr="rule", **kw): frame = __frame or sys._getframe(2) name = __name if isinstance(rule, types.FunctionType): # only pick up name if a function if frame.f_locals.get(rule.__name__) is rule: # and locally-defined! name = name or rule.__name__ def callback(frame, name, rule, locals): kw[__ruleattr] = named_lambda(rule, name) return __proptype(__name__=name, **kw) if name: # Have everything we need, just go for it return callback(frame, name, rule, None) elif rule is not None: # We know everything but the name, so return the rule as-is and trap # the assignment... try: # TODO: check instancemethod/function/(not a lambda)? name = rule.__name__ if name == "<lambda>": decorators.decorate_assignment(callback, frame=frame) return rule # print name except: decorators.decorate_assignment(callback, frame=frame) else: return callback(frame, name, rule, None) return rule else: # We're being used as a decorator, so just decorate. return decorators.decorate_assignment(callback, frame=frame)
def abstract(func=None): """Declare a function to be abstract""" if func is None: return decorate_assignment( lambda f, n, func, old: Dispatching(func).as_abstract()) else: return Dispatching(func).as_abstract()
def on(argument_name): """Please switch to using @peak.rules.abstract()""" def callback(frm, name, value, old_locals): import inspect funcname = value.__name__ args, varargs, kwargs, defaults = inspect.getargspec(value) if argument_name not in args: raise NameError("%r does not have an argument named %r" % (value, argument_name)) argpos = args.index(argument_name) func = value def when(cond): """Add following function to this GF, using 'cond' as a guard""" def callback(frm, name, value, old_locals): core.when(func, (object, ) * argpos + (cond, ))(value) if old_locals.get(name) is func: return func return value return decorate_assignment(callback) def clone(): raise AssertionError("PEAK-Rules can't clone() generic functions") func.when = when func.clone = clone return core.abstract(func) return decorate_assignment(callback)
def nodetype(*mixins, **kw): def callback(frame, name, func, old_locals): def __new__(cls, *args, **kw): result = func(*args, **kw) if type(result) is tuple: return tuple.__new__(cls, (cls,)+result) else: return result def __repr__(self): r = self.__class__.__name__ + tuple.__repr__(self[1:]) if len(self)==2: return r[:-2]+')' # nix trailing ',' return r def __call__(self, code): return func(*(self[1:]+(code,))) import inspect args = inspect.getargspec(func)[0] d = dict( __new__ = __new__, __repr__ = __repr__, __doc__=func.__doc__, __module__ = func.__module__, __args__ = args, __slots__ = [], __call__ = __call__ ) for p,a in enumerate(args[:-1]): # skip 'code' argument if isinstance(a,str): d[a] = property(lambda self, p=p+1: self[p]) d.update(kw) return type(name, mixins+(Node,), d) return decorate_assignment(callback)
def on(argument_name): """Please switch to using @peak.rules.abstract()""" def callback(frm,name,value,old_locals): import inspect funcname = value.__name__ args, varargs, kwargs, defaults = inspect.getargspec(value) if argument_name not in args: raise NameError("%r does not have an argument named %r" % (value, argument_name)) argpos = args.index(argument_name) func = value def when(cond): """Add following function to this GF, using 'cond' as a guard""" def callback(frm,name,value,old_locals): core.when(func, (object,)*argpos + (cond,))(value) if old_locals.get(name) is func: return func return value return decorate_assignment(callback) def clone(): raise AssertionError("PEAK-Rules can't clone() generic functions") func.when = when func.clone = clone return core.abstract(func) return decorate_assignment(callback)
def _decorate(self, cond, qualifier=None, frame=None, depth=2): # XXX frame = frame or sys._getframe(depth) cond = self.parseRule(cond, frame=frame) or cond def registerMethod(frm, name, value, old_locals): if qualifier is None: func = value else: func = qualifier, value kind, module, locals_, globals_ = frameinfo(frm) if kind == 'class': # 'when()' in class body; defer adding the method def registerClassSpecificMethod(cls): req = strategy.Signature([(strategy.Argument(0), ICriterion(cls))]) self.addMethod(req & cond, func) return cls decorate_class(registerClassSpecificMethod, frame=frm) else: self.addMethod(cond, func) if old_locals.get(name) in (self, self.delegate): return self.delegate return value return decorate_assignment(registerMethod, frame=frame)
def _hook_method(self, methodname, func=None, frame=None): if not self.can_connect(): raise TypeError("%r cannot have a .%sor" % (self, methodname)) if isinstance(self.rule, AbstractConnector): raise TypeError("The rule for %r is itself a Connector" % (self,)) if getattr(self, methodname) is not None: raise TypeError("%r already has a .%sor" % (self, methodname)) if func is not None: setattr(self, methodname, func) if getattr(func, "__name__", None) == self.__name__: frame = frame or sys._getframe(2) if frame.f_locals.get(self.__name__) is self: return self return func frame = frame or sys._getframe(2) def callback(frame, name, func, locals): setattr(self, methodname, func) if name == self.__name__ and locals.get(name) is self: return self return func return decorators.decorate_assignment(callback, frame=frame)
def _decorate(self,cond,qualifier=None,frame=None,depth=2): # XXX frame = frame or sys._getframe(depth) cond = self.parseRule(cond,frame=frame) or cond def registerMethod(frm,name,value,old_locals): if qualifier is None: func = value else: func = qualifier,value kind,module,locals_,globals_ = frameinfo(frm) if kind=='class': # 'when()' in class body; defer adding the method def registerClassSpecificMethod(cls): req = strategy.Signature( [(strategy.Argument(0),ICriterion(cls))] ) self.addMethod(req & cond, func) return cls decorate_class(registerClassSpecificMethod,frame=frm) else: self.addMethod(cond,func) if old_locals.get(name) in (self,self.delegate): return self.delegate return value return decorate_assignment(registerMethod,frame=frame)
def when(cond): """Add following function to this GF, using 'cond' as a guard""" def callback(frm,name,value,old_locals): core.when(func, (object,)*argpos + (cond,))(value) if old_locals.get(name) is func: return func return value return decorate_assignment(callback)
def when(cond): """Add following function to this GF, using 'cond' as a guard""" def callback(frm,name,value,old_locals): declarePredicate(cond, protocol, lambda ob: (ob,value)) if old_locals.get(name) is func: return func return value return decorate_assignment(callback)
def abstract(func=None): """Declare a function to be abstract""" if func is None: return decorate_assignment( lambda f,n,func,old: Dispatching(func).as_abstract() ) else: return Dispatching(func).as_abstract()
def when(cond): """Add following function to this GF, using 'cond' as a guard""" def callback(frm, name, value, old_locals): declarePredicate(cond, protocol, lambda ob: (ob, value)) if old_locals.get(name) is func: return func return value return decorate_assignment(callback)
def as_(*decorators): """Please switch to using @peak.util.decorators.decorate""" warn("Please use @peak.util.decorators.decorate instead of dispatch.as()", DeprecationWarning, 2 ) def callback(frame,k,v,old_locals): for d in decorators[::-1]: v = d(v) return v return decorate_assignment(callback)
def when(cond): """Add following function to this GF, using 'cond' as a guard""" def callback(frm, name, value, old_locals): core.when(func, (object, ) * argpos + (cond, ))(value) if old_locals.get(name) is func: return func return value return decorate_assignment(callback)
def make_module(): def callback(frm, name, value, old_locals): m = new.module('dispatch.'+name) v = value() m.__dict__.update(v) m.__all__ = list(v) sys.modules.setdefault(m.__name__, m) sys.modules.setdefault('peak.rules.'+m.__name__, m) return m return decorate_assignment(callback)
def generic(combiner=None): """Use the following function as the skeleton for a generic function Decorate a Python function so that it wraps an instance of 'dispatch.functions.GenericFunction' that has been configured with the decorated function's name, docstring, argument signature, and default arguments. The decorated function will have additional attributes besides those of a normal function. (See 'dispatch.IGenericFunction' for more information on these special attributes/methods.) Most commonly, you will use the 'when()' method of the decorated function to define "rules" or "methods" of the generic function. For example:: import dispatch @dispatch.generic() def someFunction(*args): '''This is a generic function''' @someFunction.when("len(args)>0") def argsPassed(*args): print "Arguments were passed!" @someFunction.when("len(args)==0") def noArgsPassed(*args): print "No arguments were passed!" someFunction() # prints "No args passed" someFunction(1) # prints "args passed" Note that when using older Python versions, you must use '[dispatch.generic()]' instead of '@dispatch.generic()'. """ from dispatch.functions import GenericFunction, AbstractGeneric from peak.util.decorators import decorate_assignment if combiner is None: def callback(frm, name, value, old_locals): return GenericFunction(value).delegate elif isinstance(combiner, _cls) and issubclass(combiner, AbstractGeneric): def callback(frm, name, value, old_locals): return combiner(value).delegate else: def callback(frm, name, value, old_locals): gf = GenericFunction(value) gf.combine = combiner return gf.delegate return decorate_assignment(callback)
def make_module(): def callback(frm, name, value, old_locals): m = types.ModuleType('dispatch.' + name) v = value() m.__dict__.update(v) m.__all__ = list(v) sys.modules.setdefault(m.__name__, m) sys.modules.setdefault('peak.rules.' + m.__name__, m) return m return decorate_assignment(callback)
def as_(*decorators): """Please switch to using @peak.util.decorators.decorate""" warn("Please use @peak.util.decorators.decorate instead of dispatch.as()", DeprecationWarning, 2) def callback(frame, k, v, old_locals): for d in decorators[::-1]: v = d(v) return v return decorate_assignment(callback)
def generic(combiner=None): """Use the following function as the skeleton for a generic function Decorate a Python function so that it wraps an instance of 'dispatch.functions.GenericFunction' that has been configured with the decorated function's name, docstring, argument signature, and default arguments. The decorated function will have additional attributes besides those of a normal function. (See 'dispatch.IGenericFunction' for more information on these special attributes/methods.) Most commonly, you will use the 'when()' method of the decorated function to define "rules" or "methods" of the generic function. For example:: import dispatch @dispatch.generic() def someFunction(*args): '''This is a generic function''' @someFunction.when("len(args)>0") def argsPassed(*args): print "Arguments were passed!" @someFunction.when("len(args)==0") def noArgsPassed(*args): print "No arguments were passed!" someFunction() # prints "No args passed" someFunction(1) # prints "args passed" Note that when using older Python versions, you must use '[dispatch.generic()]' instead of '@dispatch.generic()'. """ from dispatch.functions import GenericFunction, AbstractGeneric from peak.util.decorators import decorate_assignment if combiner is None: def callback(frm,name,value,old_locals): return GenericFunction(value).delegate elif isinstance(combiner,_cls) and issubclass(combiner,AbstractGeneric): def callback(frm,name,value,old_locals): return combiner(value).delegate else: def callback(frm,name,value,old_locals): gf = GenericFunction(value) gf.combine = combiner return gf.delegate return decorate_assignment(callback)
def meta_function(*stub, **parsers): """Declare a meta-function and its argument parsers""" stub, = stub def callback(frame, name, func, old_locals): for name in inspect.getargs(func.func_code)[0]: if not isinstance(name, basestring): raise TypeError( "Meta-functions cannot have packed-tuple arguments" ) what = func, parsers, inspect.getargspec(func) meta_functions[stub] = ( lambda builder, *args: apply_meta(builder, what, *args) ) return func return decorate_assignment(callback)
def meta_function(*stub, **parsers): """Declare a meta-function and its argument parsers""" stub, = stub def callback(frame, name, func, old_locals): for name in inspect.getargs(func.func_code)[0]: if not isinstance(name, basestring): raise TypeError( "Meta-functions cannot have packed-tuple arguments") what = func, parsers, inspect.getargspec(func) meta_functions[stub] = ( lambda builder, *args: apply_meta(builder, what, *args)) return func return decorate_assignment(callback)
def weak_signature_decorator(entangler): """Decorate function with entangler and change signature to accept arbitrary additional arguments. Enables alternative decorator syntax for Python 2.3 as seen in PEAK: [my_decorator(foo)] def baz(): pass Mind, the decorator needs to be a closure for this syntax to work. """ def callback(frame, k, v, old_locals): return decorate(v, entangler(v), make_weak_signature(v)) return decorate_assignment(callback, 3)
def decorator(entangler, signature=None): """Decorate function with entangler. Use signature as signature or preserve original signature if signature is None. Enables alternative decorator syntax for Python 2.3 as seen in PEAK: [my_decorator(foo)] def baz(): pass Mind, the decorator needs to be a closure for this syntax to work. """ def callback(frame, k, v, old_locals): return decorate(v, entangler(v), signature) return decorate_assignment(callback, 3)
def generic(combiner=None): """Please switch to using @peak.rules.abstract()""" if combiner is not None: raise AssertionError( "Custom combiners are not supported by the compatibility API;" " please use a custom method type instead" ) def callback(frm,name,value,old_locals): value.when = core.when.__get__(value) value.around = core.around.__get__(value) value.before = core.before.__get__(value) value.after = core.after.__get__(value) def clear(): core.rules_for(value).clear() value.clear = clear return core.abstract(value) return decorate_assignment(callback)
def decorate(f, pred=(), depth=2, frame=None): def callback(frame, name, func, old_locals): assert f is not func # XXX kind, module, locals_, globals_ = frameinfo(frame) context = ParseContext(func, maker, locals_, globals_, lineno) def register_for_class(cls, f=f): _register_rule(f, pred, context, cls) return cls if kind=='class': # 'when()' in class body; defer adding the method decorate_class(register_for_class, frame=frame) else: register_for_class(None) if old_locals.get(name) is f: return f # prevent overwriting if name is the same return func rv = decorate_assignment(callback, depth, frame) if frame is None: frame = sys._getframe(depth-1) lineno = frame.f_lineno # this isn't valid w/out active trace! return rv
def generic(combiner=None): """Please switch to using @peak.rules.abstract()""" if combiner is not None: raise AssertionError( "Custom combiners are not supported by the compatibility API;" " please use a custom method type instead") def callback(frm, name, value, old_locals): value.when = core.when.__get__(value) value.around = core.around.__get__(value) value.before = core.before.__get__(value) value.after = core.after.__get__(value) def clear(): core.rules_for(value).clear() value.clear = clear return core.abstract(value) return decorate_assignment(callback)
def nodetype(*mixins, **kw): def callback(frame, name, func, old_locals): def __new__(cls, *args, **kw): result = func(*args, **kw) if type(result) is tuple: return tuple.__new__(cls, (cls,) + result) else: return result def __repr__(self): r = self.__class__.__name__ + tuple.__repr__(self[1:]) if len(self) == 2: return r[:-2] + ")" # nix trailing ',' return r def __call__(self, code): return func(*(self[1:] + (code,))) import inspect args = inspect.getargspec(func)[0] d = dict( __new__=__new__, __repr__=__repr__, __doc__=func.__doc__, __module__=func.__module__, __args__=args, __slots__=[], __call__=__call__, ) for p, a in enumerate(args[:-1]): # skip 'code' argument if isinstance(a, str): d[a] = property(lambda self, p=p + 1: self[p]) d.update(kw) return type(name, mixins + (Node,), d) return decorate_assignment(callback)
def on(argument_name): """Decorate the following function as a single-dispatch generic function Single-dispatch generic functions may have a slight speed advantage over predicate-dispatch generic functions when you only need to dispatch based on a single argument's type or protocol, and do not need arbitrary predicates. Also, single-dispatch functions do not require you to adapt the dispatch argument when dispatching based on protocol or interface, and if the dispatch argument has a '__conform__' method, it will attempt to use it, rather than simply dispatching based on class information the way predicate dispatch functions do. The created generic function will use the documentation from the supplied function as its docstring. And, it will dispatch methods based on the argument named by 'argument_name', and otherwise keeping the same argument signature, defaults, etc. For example:: @dispatch.on('y') def doSomething(x,y,z): '''Doc for 'doSomething()' generic function goes here''' @doSomething.when([SomeClass,OtherClass]) def doSomething(x,y,z): # do something when 'isinstance(y,(SomeClass,OtherClass))' @doSomething.when(IFoo) def doSomething(x,y,z): # do something to a 'y' that has been adapted to 'IFoo' """ def callback(frm,name,value,old_locals): return _mkGeneric(value,argument_name) from dispatch.functions import _mkGeneric from peak.util.decorators import decorate_assignment return decorate_assignment(callback)
def on(argument_name): """Decorate the following function as a single-dispatch generic function Single-dispatch generic functions may have a slight speed advantage over predicate-dispatch generic functions when you only need to dispatch based on a single argument's type or protocol, and do not need arbitrary predicates. Also, single-dispatch functions do not require you to adapt the dispatch argument when dispatching based on protocol or interface, and if the dispatch argument has a '__conform__' method, it will attempt to use it, rather than simply dispatching based on class information the way predicate dispatch functions do. The created generic function will use the documentation from the supplied function as its docstring. And, it will dispatch methods based on the argument named by 'argument_name', and otherwise keeping the same argument signature, defaults, etc. For example:: @dispatch.on('y') def doSomething(x,y,z): '''Doc for 'doSomething()' generic function goes here''' @doSomething.when([SomeClass,OtherClass]) def doSomething(x,y,z): # do something when 'isinstance(y,(SomeClass,OtherClass))' @doSomething.when(IFoo) def doSomething(x,y,z): # do something to a 'y' that has been adapted to 'IFoo' """ def callback(frm, name, value, old_locals): return _mkGeneric(value, argument_name) from dispatch.functions import _mkGeneric from peak.util.decorators import decorate_assignment return decorate_assignment(callback)
def dispatch_as(*decorators): """Use Python 2.4 decorators w/Python 2.2+ Example: import dispatch class Foo(object): [dispatch.as(classmethod)] def something(cls,etc): \"""This is a classmethod\""" """ if len(decorators) > 1: decorators = list(decorators) decorators.reverse() def callback(frame, k, v, old_locals): for d in decorators: v = d(v) return v from peak.util.decorators import decorate_assignment return decorate_assignment(callback)
def dispatch_as(*decorators): """Use Python 2.4 decorators w/Python 2.2+ Example: import dispatch class Foo(object): [dispatch.as(classmethod)] def something(cls,etc): \"""This is a classmethod\""" """ if len(decorators)>1: decorators = list(decorators) decorators.reverse() def callback(frame,k,v,old_locals): for d in decorators: v = d(v) return v from peak.util.decorators import decorate_assignment return decorate_assignment(callback)
def add_assignment_advisor(callback,depth=2,frame=None): "protocols.advice.add_assignment_advisor is deprecated, please use" " peak.util.decorators.decorate_assignment instead" from warnings import warn warn(add_assignment_advisor.__doc__, DeprecationWarning, 2) return decorators.decorate_assignment(callback, (depth or 0)+1, frame)
def add_assignment_advisor(callback, depth=2, frame=None): "protocols.advice.add_assignment_advisor is deprecated, please use" " peak.util.decorators.decorate_assignment instead" from warnings import warn warn(add_assignment_advisor.__doc__, DeprecationWarning, 2) return decorators.decorate_assignment(callback, (depth or 0) + 1, frame)