Package logilab :: Package common :: Module decorators
[frames] | no frames]

Source Code for Module logilab.common.decorators

  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  # XXX rewrite so we can use the decorator syntax when keyarg has to be specified 
 14   
15 -def cached(callableobj, keyarg=None):
16 """Simple decorator to cache result of method call.""" 17 #print callableobj, keyarg, callableobj.func_code.co_argcount 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 #print 'cache1?', cache 23 try: 24 return self.__dict__[cache] 25 except KeyError: 26 #print 'miss' 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 #print 'cache2?', cache, self, key 38 try: 39 _cache = self.__dict__[cache] 40 except KeyError: 41 #print 'init' 42 _cache = {} 43 setattr(self, cache, _cache) 44 try: 45 return _cache[key] 46 except KeyError: 47 #print 'miss', self, cache, key 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 #print 'cache3?', cache, self, args 55 try: 56 _cache = self.__dict__[cache] 57 except KeyError: 58 #print 'init' 59 _cache = {} 60 setattr(self, cache, _cache) 61 try: 62 return _cache[args] 63 except KeyError: 64 #print 'miss' 65 _cache[args] = callableobj(self, *args) 66 return _cache[args] 67 return cache_wrapper3 68
69 -def clear_cache(obj, funcname):
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
76 -def copy_cache(obj, funcname, cacheobj):
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
84 -class wproperty(object):
85 """Simple descriptor expecting to take a modifier function as first argument 86 and looking for a _<function name> to retrieve the attribute. 87 """
88 - def __init__(self, setfunc):
89 self.setfunc = setfunc 90 self.attrname = '_%s' % setfunc.__name__
91
92 - def __set__(self, obj, value):
93 self.setfunc(obj, value)
94
95 - def __get__(self, obj, cls):
96 assert obj is not None 97 return getattr(obj, self.attrname)
98 99
100 -class classproperty(object):
101 """this is a simple property-like class but for class attributes. 102 """
103 - def __init__(self, get):
104 self.get = get
105 - def __get__(self, inst, cls):
106 return self.get(cls)
107 108
109 -class iclassmethod(object):
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 '''
113 - def __init__(self, func):
114 self.func = func
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
123 -def timed(f):
124 def wrap(*args, **kwargs): 125 t = clock() 126 #for i in range(100): 127 res = f(*args, **kwargs) 128 print '%s time: %.9f' % (f.__name__, clock() - t) 129 return res
130 return wrap 131 132
133 -def locked(acquire, release):
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
149 -def monkeypatch(klass, methodname=None):
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