1 """Decorator tools"""
2
3 __all__ = ['decorate', 'make_weak_signature', 'compose',
4 'decorator', 'weak_signature_decorator',
5 'simple_decorator', 'simple_weak_signature_decorator',
6 'func_id', 'func_eq', 'func_original', 'func_composition']
7
8 import itertools
9 from inspect import getargspec, formatargspec
10
11
12 -def decorate(func, caller, signature=None):
13 """Decorate func with caller.
14
15 Inspired by Michele Simionato's decorator library:
16 http://www.phyast.pitt.edu/~micheles/python/documentation.html
17
18 """
19 argnames, varargs, kwargs, defaults = \
20 signature is None and getargspec(func) or signature
21 if defaults is None:
22 defaults = ()
23 parameters = formatargspec(argnames, varargs, kwargs, defaults)[1:-1]
24 defval = itertools.count(len(argnames) - len(defaults))
25 args = formatargspec(argnames, varargs, kwargs, defaults,
26 formatvalue=lambda value:"=%s" % argnames[defval.next()])[1:-1]
27 exec_dict = dict(func=func, caller=caller)
28 exec "\ndef %s(%s):\n\treturn caller(func, %s)\n" % (
29 func.__name__, parameters, args) in exec_dict
30 new_func = exec_dict[func.__name__]
31 new_func.__doc__ = func.__doc__
32 new_func.__dict__ = func.__dict__.copy()
33 new_func.__module__ = func.__module__
34 new_func.__composition__ = getattr(func, '__composition__',
35 [func]) + [new_func]
36 return new_func
37
38
40 """Decorate function with entangler.
41
42 Use new signature or preserve original signature if signature is None.
43
44 """
45 def entangle(func):
46 return decorate(func, entangler(func), signature)
47 return entangle
48
49
51 """Decorate function with entangler and weak signature.
52
53 Changes signature to accept arbitrary additional arguments.
54
55 """
56 def entangle(func):
57 return decorate(func, entangler(func), make_weak_signature(func))
58 return entangle
59
60
62 """Decorate function with caller."""
63 def entangle(func):
64 return decorate(func, caller, signature)
65 return entangle
66
67
69 """Decorate function with caller and weak signature.
70
71 Changes signature to accept arbitrary additional arguments.
72
73 """
74 def entangle(func):
75 return decorate(func, caller, make_weak_signature(func))
76 return entangle
77
78
80 """Change signature to accept arbitrary additional arguments."""
81 argnames, varargs, kwargs, defaults = getargspec(func)
82 if kwargs is None:
83 kwargs = "_decorator__kwargs"
84 if varargs is None:
85 varargs = "_decorator__varargs"
86 return argnames, varargs, kwargs, defaults
87
88
90 """Compose decorators."""
91 return lambda func: reduce(lambda f, g: g(f), decorators, func)
92
93
95 """Return composition (decorator wise) of function."""
96 return getattr(func, "__composition__", [func])
97
98
100 """Return original (undecorated) function."""
101 return func_composition(func)[0]
102
103
105 """Return identity of function.
106
107 If decorator was created with decorator() or weak_signature_decorator(),
108 identity is invariant under decorator application.
109
110 """
111 return id(func_original(func))
112
113
115 """Check if functions are identical."""
116 return func_id(f) == func_id(g)
117