1 """A few useful function/method decorators.
2
3 :copyright: 2006-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
4 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
5 :license: General Public License version 2 - http://www.gnu.org/licenses
6 """
7 __docformat__ = "restructuredtext en"
8
9 from types import MethodType
10 from time import clock
11 import sys, re
12
13
14
15 -def cached(callableobj, keyarg=None):
16 """Simple decorator to cache result of method call."""
17
18 if callableobj.func_code.co_argcount == 1 or keyarg == 0:
19
20 def cache_wrapper1(self, *args):
21 cache = '_%s_cache_' % callableobj.__name__
22
23 try:
24 return self.__dict__[cache]
25 except KeyError:
26
27 value = callableobj(self, *args)
28 setattr(self, cache, value)
29 return value
30 return cache_wrapper1
31
32 elif keyarg:
33
34 def cache_wrapper2(self, *args, **kwargs):
35 cache = '_%s_cache_' % callableobj.__name__
36 key = args[keyarg-1]
37
38 try:
39 _cache = self.__dict__[cache]
40 except KeyError:
41
42 _cache = {}
43 setattr(self, cache, _cache)
44 try:
45 return _cache[key]
46 except KeyError:
47
48 _cache[key] = callableobj(self, *args, **kwargs)
49 return _cache[key]
50 return cache_wrapper2
51
52 def cache_wrapper3(self, *args):
53 cache = '_%s_cache_' % callableobj.__name__
54
55 try:
56 _cache = self.__dict__[cache]
57 except KeyError:
58
59 _cache = {}
60 setattr(self, cache, _cache)
61 try:
62 return _cache[args]
63 except KeyError:
64
65 _cache[args] = callableobj(self, *args)
66 return _cache[args]
67 return cache_wrapper3
68
70 """Function to clear a cache handled by the cached decorator."""
71 try:
72 del obj.__dict__['_%s_cache_' % funcname]
73 except KeyError:
74 pass
75
77 """Copy cache for <funcname> from cacheobj to obj."""
78 cache = '_%s_cache_' % funcname
79 try:
80 setattr(obj, cache, cacheobj.__dict__[cache])
81 except KeyError:
82 pass
83
85 """Simple descriptor expecting to take a modifier function as first argument
86 and looking for a _<function name> to retrieve the attribute.
87 """
89 self.setfunc = setfunc
90 self.attrname = '_%s' % setfunc.__name__
91
93 self.setfunc(obj, value)
94
96 assert obj is not None
97 return getattr(obj, self.attrname)
98
99
101 """this is a simple property-like class but for class attributes.
102 """
107
108
110 '''Descriptor for method which should be available as class method if called
111 on the class or instance method if called on an instance.
112 '''
115 - def __get__(self, instance, objtype):
116 if instance is None:
117 return MethodType(self.func, objtype, objtype.__class__)
118 return MethodType(self.func, instance, objtype)
119 - def __set__(self, instance, value):
120 raise AttributeError("can't set attribute")
121
122
124 def wrap(*args, **kwargs):
125 t = clock()
126
127 res = f(*args, **kwargs)
128 print '%s time: %.9f' % (f.__name__, clock() - t)
129 return res
130 return wrap
131
132
134 """Decorator taking two methods to acquire/release a lock as argument,
135 returning a decorator function which will call the inner method after
136 having called acquire(self) et will call release(self) afterwards.
137 """
138 def decorator(f):
139 def wrapper(self, *args, **kwargs):
140 acquire(self)
141 try:
142 return f(self, *args, **kwargs)
143 finally:
144 release(self)
145 return wrapper
146 return decorator
147
148
150 """Decorator extending class with the decorated function
151 >>> class A:
152 ... pass
153 >>> @monkeypatch(A)
154 ... def meth(self):
155 ... return 12
156 ...
157 >>> a = A()
158 >>> a.meth()
159 12
160 >>> @monkeypatch(A, 'foo')
161 ... def meth(self):
162 ... return 12
163 ...
164 >>> a.foo()
165 12
166 """
167 def decorator(func):
168 setattr(klass, methodname or func.__name__, func)
169 return func
170 return decorator
171