1
2
3
4 """
5 Decorators and decorator utilities.
6
7 @todo: Move the actual decorators to modules based on their topic.
8 """
9
10 from __future__ import with_statement
11 import functools, inspect, xmlrpclib
12 from cPickle import *
15 """
16 Prevents a methods from recursively calling itself. On recursion, it will
17 return retval instead. Note that this only protects methods, not functions.
18 To implement something similar for functions may call for some thread-local
19 state or some stack-walking.
20 """
21 def decorator(func):
22 @functools.wraps(func)
23 def wrapper(self, *args, **kw):
24 if getattr(self, guard_name, False):
25 return retval
26 setattr(self, guard_name, True)
27 try:
28 return func(self, *args, **kw)
29 finally:
30 setattr(self, guard_name, False)
31 return wrapper
32 return decorator
33
35 """
36 Wrap any callable with before/after calls.
37
38 From the Python Cookbook. Modified to support C{None} for
39 C{before} or C{after}.
40
41 @copyright: O'Reilly Media
42
43 @param any_callable: The function to decorate.
44 @type any_callable: function
45
46 @param before: The pre-processing procedure. If this is C{None}, then no pre-processing will be done.
47 @type before: function
48
49 @param after: The post-processing procedure. If this is C{None}, then no post-processing will be done.
50 @type after: function
51 """
52 def _wrapped(*a, **kw):
53 if before is not None:
54 before( )
55 try:
56 return any_callable(*a, **kw)
57 finally:
58 if after is not None:
59 after( )
60
61 return _wrapped
62
64 """
65 Wrap all of an object's methods with before/after calls. This is
66 like a decorator for objects.
67
68 From the I{Python Cookbook}.
69
70 @copyright: O'Reilly Media
71 """
72 - def __init__(self, obj, before, after, ignore=( )):
73
74
75 clasname = 'GenericWrapper'
76 self.__dict__['_%s__methods' % clasname] = { }
77 self.__dict__['_%s__obj' % clasname] = obj
78 for name, method in inspect.getmembers(obj, inspect.ismethod):
79 if name not in ignore and method not in ignore:
80 self.__methods[name] = wrap_callable(method, before, after)
82 try:
83 return self.__methods[name]
84 except KeyError:
85 return getattr(self.__obj, name)
87 setattr(self.__obj, name, value)
88
92 """
93 Makes a procedure "XMLRPC-safe" by returning 0 whenever the inner
94 function returns C{None}. This is useful because XMLRPC requires
95 return values, and 0 is commonly used when functions don't intend
96 to return anything.
97
98 Also, if the procedure returns a boolean, it will be wrapped in
99 C{xmlrpclib.Boolean}.
100
101 @param func: The procedure to decorate.
102 @type func: function
103 """
104 @functools.wraps(func)
105 def wrapper(*args,**kwargs):
106 result = func(*args,**kwargs)
107 if result is not None:
108 if type( result ) == bool:
109 return xmlrpclib.Boolean( result )
110 else:
111 return result
112 else:
113 return 0
114 return wrapper
115
119 """
120 The string result of the given function is saved to the given path.
121
122 Example::
123
124 @file_memoized(lambda x,f: f.write(x),
125 lambda f: f.read(),
126 lambda: "/tmp/cache")
127 def foo(): return "hello"
128
129 @file_memoized(pickle.dump,
130 pickle.load,
131 lambda x,y: "/tmp/cache-%d-%d" % (x,y))
132 def foo(x,y): return "hello %d %d" % (x,y)
133
134 @param serializer: The function to serialize the return value into a
135 string. This should take the return value object and
136 the file object.
137 @type serializer: function
138
139 @param deserializer: The function te deserialize the cache file contents
140 into the return value. This should take the file
141 object and return a string.
142 @type deserializer: function
143
144 @param pathfunc: Returns the path where the files should be saved. This
145 should be able to take the same arguments as the original
146 function.
147 @type pathfunc: str
148 """
149 def dec(func):
150 @functools.wraps(func)
151 def wrapper(*args, **kwargs):
152 p = pathfunc(*args, **kwargs)
153 try:
154 with file(p) as f:
155 return deserializer(f)
156 except IOError, (errno, errstr):
157 if errno != 2: raise
158 with file(p, 'w') as f:
159 x = func(*args, **kwargs)
160 serializer(x, f)
161 return x
162 return wrapper
163 return dec
164
166 """
167 Wrapper around L{file_memoized} that expects the decorated function to
168 return strings, so the string is written verbatim.
169 """
170 return file_memoized(lambda x,f: f.write(x), lambda f: f.read(), pathfunc)
171
173 """
174 Wrapper around L{file_memoized} that uses pickle.
175 """
176 bindump = lambda x,f: dump(x,f,2)
177 binload = lambda x,f: load(x,f,2)
178 return file_memoized(bindump, binload, pathfunc)
179