1 import itertools
2 from copy import copy
3 from inspect import getargspec, formatargspec
4
5 from peak.util.decorators import decorate_assignment
6
7
8
9
10
11 -def decorate(func, caller, signature=None):
12 """Decorate func with caller."""
13 if signature is not None:
14 argnames, varargs, kwargs, defaults = signature
15 else:
16 argnames, varargs, kwargs, defaults = getargspec(func)
17 if defaults is None:
18 defaults = ()
19 parameters = formatargspec(argnames, varargs, kwargs, defaults)[1:-1]
20 defval = itertools.count(len(argnames)-len(defaults))
21 args = formatargspec(argnames, varargs, kwargs, defaults,
22 formatvalue=lambda value:"=%s" % (
23 argnames[defval.next()]))[1:-1]
24
25 func_str = """
26 def %s(%s):
27 return caller(func, %s)
28 """ % (func.__name__, parameters, args)
29
30 exec_dict = dict(func=func, caller=caller)
31 exec func_str in exec_dict
32 newfunc = exec_dict[func.__name__]
33 newfunc.__doc__ = func.__doc__
34 newfunc.__dict__ = func.__dict__.copy()
35 newfunc.__module__ = func.__module__
36 if hasattr(func, "__composition__"):
37 newfunc.__composition__ = copy(func.__composition__)
38 else:
39 newfunc.__composition__ = [func]
40 newfunc.__composition__.append(newfunc)
41 return newfunc
42
44 """Decorate function with entangler.
45
46 Use signature as signature or preserve original signature if signature
47 is None.
48
49 Enables alternative decorator syntax for Python 2.3 as seen in PEAK:
50
51 [my_decorator(foo)]
52 def baz():
53 pass
54
55 Mind, the decorator needs to be a closure for this syntax to work.
56 """
57 def callback(frame, k, v, old_locals):
58 return decorate(v, entangler(v), signature)
59 return decorate_assignment(callback, 3)
60
62 """Decorate function with entangler and change signature to accept
63 arbitrary additional arguments.
64
65 Enables alternative decorator syntax for Python 2.3 as seen in PEAK:
66
67 [my_decorator(foo)]
68 def baz():
69 pass
70
71 Mind, the decorator needs to be a closure for this syntax to work.
72 """
73 def callback(frame, k, v, old_locals):
74 return decorate(v, entangler(v), make_weak_signature(v))
75 return decorate_assignment(callback, 3)
76
78 """Decorate function with caller."""
79 def entangle(func):
80 return decorate(func, caller, signature)
81 return entangle
82
84 """Decorate function with caller and change signature to accept
85 arbitrary additional arguments."""
86 def entangle(func):
87 return decorate(func, caller, make_weak_signature(func))
88 return entangle
89
91 """Change signature to accept arbitrary additional arguments."""
92 argnames, varargs, kwargs, defaults = getargspec(func)
93 if kwargs is None:
94 kwargs = "_decorator__kwargs"
95 if varargs is None:
96 varargs = "_decorator__varargs"
97 return argnames, varargs, kwargs, defaults
98
100 """Compose decorators."""
101 return lambda func: reduce(lambda f, g: g(f), decorators, func)
102
104 """Return composition (decorator wise) of function."""
105 return getattr(func, "__composition__", [func])
106
108 """Return original (undecorated) function."""
109 return func_composition(func)[0]
110
112 """Return identity of function.
113
114 Identity is invariant under decorator application (if decorator is
115 created with decorator() or weak_signature_decorator()).
116 """
117 return id(func_original(func))
118
120 """Check if functions are identical."""
121 return func_id(f) == func_id(g)
122
123 __all__ = ["decorator", "compose", "func_id", "func_eq", "func_original",
124 "func_composition", "weak_signature_decorator", "decorate",
125 "make_weak_signature", "simple_decorator",
126 "simple_weak_signature_decorator",]
127