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

Source Code for Module logilab.common.decorators

  1  # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 
  2  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 
  3  # 
  4  # This file is part of logilab-common. 
  5  # 
  6  # logilab-common is free software: you can redistribute it and/or modify it under 
  7  # the terms of the GNU Lesser General Public License as published by the Free 
  8  # Software Foundation, either version 2.1 of the License, or (at your option) any 
  9  # later version. 
 10  # 
 11  # logilab-common is distributed in the hope that it will be useful, but WITHOUT 
 12  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
 13  # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 14  # details. 
 15  # 
 16  # You should have received a copy of the GNU Lesser General Public License along 
 17  # with logilab-common.  If not, see <http://www.gnu.org/licenses/>. 
 18  """A few useful function/method decorators. 
 19   
 20   
 21   
 22   
 23  """ 
 24  __docformat__ = "restructuredtext en" 
 25   
 26  from types import MethodType 
 27  from time import clock, time 
 28  import sys, re 
 29   
 30  # XXX rewrite so we can use the decorator syntax when keyarg has to be specified 
 31   
32 -def cached(callableobj, keyarg=None):
33 """Simple decorator to cache result of method call.""" 34 if callableobj.func_code.co_argcount == 1 or keyarg == 0: 35 36 def cache_wrapper1(self, *args): 37 cache = '_%s_cache_' % callableobj.__name__ 38 #print 'cache1?', cache 39 try: 40 return self.__dict__[cache] 41 except KeyError: 42 #print 'miss' 43 value = callableobj(self, *args) 44 setattr(self, cache, value) 45 return value
46 cache_wrapper1.__doc__ = callableobj.__doc__ 47 return cache_wrapper1 48 49 elif keyarg: 50 51 def cache_wrapper2(self, *args, **kwargs): 52 cache = '_%s_cache_' % callableobj.__name__ 53 key = args[keyarg-1] 54 #print 'cache2?', cache, self, key 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[key] 63 except KeyError: 64 #print 'miss', self, cache, key 65 _cache[key] = callableobj(self, *args, **kwargs) 66 return _cache[key] 67 cache_wrapper2.__doc__ = callableobj.__doc__ 68 return cache_wrapper2 69 70 def cache_wrapper3(self, *args): 71 cache = '_%s_cache_' % callableobj.__name__ 72 #print 'cache3?', cache, self, args 73 try: 74 _cache = self.__dict__[cache] 75 except KeyError: 76 #print 'init' 77 _cache = {} 78 setattr(self, cache, _cache) 79 try: 80 return _cache[args] 81 except KeyError: 82 #print 'miss' 83 _cache[args] = callableobj(self, *args) 84 return _cache[args] 85 cache_wrapper3.__doc__ = callableobj.__doc__ 86 return cache_wrapper3 87
88 -def clear_cache(obj, funcname):
89 """Function to clear a cache handled by the cached decorator.""" 90 try: 91 del obj.__dict__['_%s_cache_' % funcname] 92 except KeyError: 93 pass
94
95 -def copy_cache(obj, funcname, cacheobj):
96 """Copy cache for <funcname> from cacheobj to obj.""" 97 cache = '_%s_cache_' % funcname 98 try: 99 setattr(obj, cache, cacheobj.__dict__[cache]) 100 except KeyError: 101 pass
102
103 -class wproperty(object):
104 """Simple descriptor expecting to take a modifier function as first argument 105 and looking for a _<function name> to retrieve the attribute. 106 """
107 - def __init__(self, setfunc):
108 self.setfunc = setfunc 109 self.attrname = '_%s' % setfunc.__name__
110
111 - def __set__(self, obj, value):
112 self.setfunc(obj, value)
113
114 - def __get__(self, obj, cls):
115 assert obj is not None 116 return getattr(obj, self.attrname)
117 118
119 -class classproperty(object):
120 """this is a simple property-like class but for class attributes. 121 """
122 - def __init__(self, get):
123 self.get = get
124 - def __get__(self, inst, cls):
125 return self.get(cls)
126 127
128 -class iclassmethod(object):
129 '''Descriptor for method which should be available as class method if called 130 on the class or instance method if called on an instance. 131 '''
132 - def __init__(self, func):
133 self.func = func
134 - def __get__(self, instance, objtype):
135 if instance is None: 136 return MethodType(self.func, objtype, objtype.__class__) 137 return MethodType(self.func, instance, objtype)
138 - def __set__(self, instance, value):
139 raise AttributeError("can't set attribute")
140 141
142 -def timed(f):
143 def wrap(*args, **kwargs): 144 t = time() 145 c = clock() 146 res = f(*args, **kwargs) 147 print '%s clock: %.9f / time: %.9f' % (f.__name__, 148 clock() - c, time() - t) 149 return res
150 return wrap 151 152
153 -def locked(acquire, release):
154 """Decorator taking two methods to acquire/release a lock as argument, 155 returning a decorator function which will call the inner method after 156 having called acquire(self) et will call release(self) afterwards. 157 """ 158 def decorator(f): 159 def wrapper(self, *args, **kwargs): 160 acquire(self) 161 try: 162 return f(self, *args, **kwargs) 163 finally: 164 release(self)
165 return wrapper 166 return decorator 167 168
169 -def monkeypatch(klass, methodname=None):
170 """Decorator extending class with the decorated function 171 >>> class A: 172 ... pass 173 >>> @monkeypatch(A) 174 ... def meth(self): 175 ... return 12 176 ... 177 >>> a = A() 178 >>> a.meth() 179 12 180 >>> @monkeypatch(A, 'foo') 181 ... def meth(self): 182 ... return 12 183 ... 184 >>> a.foo() 185 12 186 """ 187 def decorator(func): 188 setattr(klass, methodname or func.__name__, func) 189 return func
190 return decorator 191