Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: third_party/logilab/common/decorators.py

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/logilab/common/debugger.py ('k') | third_party/logilab/common/deprecation.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # 3 #
4 # This file is part of logilab-common. 4 # This file is part of logilab-common.
5 # 5 #
6 # logilab-common is free software: you can redistribute it and/or modify it unde r 6 # logilab-common is free software: you can redistribute it and/or modify it unde r
7 # the terms of the GNU Lesser General Public License as published by the Free 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) an y 8 # Software Foundation, either version 2.1 of the License, or (at your option) an y
9 # later version. 9 # later version.
10 # 10 #
11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT 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 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 13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 # details. 14 # details.
15 # 15 #
16 # You should have received a copy of the GNU Lesser General Public License along 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/>. 17 # with logilab-common. If not, see <http://www.gnu.org/licenses/>.
18 """ A few useful function/method decorators. """ 18 """ A few useful function/method decorators. """
19
20 from __future__ import print_function
21
19 __docformat__ = "restructuredtext en" 22 __docformat__ = "restructuredtext en"
20 23
21 import sys 24 import sys
25 import types
22 from time import clock, time 26 from time import clock, time
27 from inspect import isgeneratorfunction, getargspec
23 28
24 from logilab.common.compat import callable, method_type 29 from logilab.common.compat import method_type
25 30
26 # XXX rewrite so we can use the decorator syntax when keyarg has to be specified 31 # XXX rewrite so we can use the decorator syntax when keyarg has to be specified
27 32
28 def _is_generator_function(callableobj):
29 return callableobj.func_code.co_flags & 0x20
30
31 class cached_decorator(object): 33 class cached_decorator(object):
32 def __init__(self, cacheattr=None, keyarg=None): 34 def __init__(self, cacheattr=None, keyarg=None):
33 self.cacheattr = cacheattr 35 self.cacheattr = cacheattr
34 self.keyarg = keyarg 36 self.keyarg = keyarg
35 def __call__(self, callableobj=None): 37 def __call__(self, callableobj=None):
36 assert not _is_generator_function(callableobj), \ 38 assert not isgeneratorfunction(callableobj), \
37 'cannot cache generator function: %s' % callableobj 39 'cannot cache generator function: %s' % callableobj
38 if callableobj.func_code.co_argcount == 1 or self.keyarg == 0: 40 if len(getargspec(callableobj).args) == 1 or self.keyarg == 0:
39 cache = _SingleValueCache(callableobj, self.cacheattr) 41 cache = _SingleValueCache(callableobj, self.cacheattr)
40 elif self.keyarg: 42 elif self.keyarg:
41 cache = _MultiValuesKeyArgCache(callableobj, self.keyarg, self.cache attr) 43 cache = _MultiValuesKeyArgCache(callableobj, self.keyarg, self.cache attr)
42 else: 44 else:
43 cache = _MultiValuesCache(callableobj, self.cacheattr) 45 cache = _MultiValuesCache(callableobj, self.cacheattr)
44 return cache.closure() 46 return cache.closure()
45 47
46 class _SingleValueCache(object): 48 class _SingleValueCache(object):
47 def __init__(self, callableobj, cacheattr=None): 49 def __init__(self, callableobj, cacheattr=None):
48 self.callable = callableobj 50 self.callable = callableobj
(...skipping 11 matching lines...) Expand all
60 setattr(self, __me.cacheattr, value) 62 setattr(self, __me.cacheattr, value)
61 return value 63 return value
62 64
63 def closure(self): 65 def closure(self):
64 def wrapped(*args, **kwargs): 66 def wrapped(*args, **kwargs):
65 return self.__call__(*args, **kwargs) 67 return self.__call__(*args, **kwargs)
66 wrapped.cache_obj = self 68 wrapped.cache_obj = self
67 try: 69 try:
68 wrapped.__doc__ = self.callable.__doc__ 70 wrapped.__doc__ = self.callable.__doc__
69 wrapped.__name__ = self.callable.__name__ 71 wrapped.__name__ = self.callable.__name__
70 wrapped.func_name = self.callable.func_name
71 except: 72 except:
72 pass 73 pass
73 return wrapped 74 return wrapped
74 75
75 def clear(self, holder): 76 def clear(self, holder):
76 holder.__dict__.pop(self.cacheattr, None) 77 holder.__dict__.pop(self.cacheattr, None)
77 78
78 79
79 class _MultiValuesCache(_SingleValueCache): 80 class _MultiValuesCache(_SingleValueCache):
80 def _get_cache(self, holder): 81 def _get_cache(self, holder):
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 return method_type(self.func, instance, objtype) 220 return method_type(self.func, instance, objtype)
220 def __set__(self, instance, value): 221 def __set__(self, instance, value):
221 raise AttributeError("can't set attribute") 222 raise AttributeError("can't set attribute")
222 223
223 224
224 def timed(f): 225 def timed(f):
225 def wrap(*args, **kwargs): 226 def wrap(*args, **kwargs):
226 t = time() 227 t = time()
227 c = clock() 228 c = clock()
228 res = f(*args, **kwargs) 229 res = f(*args, **kwargs)
229 print '%s clock: %.9f / time: %.9f' % (f.__name__, 230 print('%s clock: %.9f / time: %.9f' % (f.__name__,
230 clock() - c, time() - t) 231 clock() - c, time() - t))
231 return res 232 return res
232 return wrap 233 return wrap
233 234
234 235
235 def locked(acquire, release): 236 def locked(acquire, release):
236 """Decorator taking two methods to acquire/release a lock as argument, 237 """Decorator taking two methods to acquire/release a lock as argument,
237 returning a decorator function which will call the inner method after 238 returning a decorator function which will call the inner method after
238 having called acquire(self) et will call release(self) afterwards. 239 having called acquire(self) et will call release(self) afterwards.
239 """ 240 """
240 def decorator(f): 241 def decorator(f):
241 def wrapper(self, *args, **kwargs): 242 def wrapper(self, *args, **kwargs):
242 acquire(self) 243 acquire(self)
243 try: 244 try:
244 return f(self, *args, **kwargs) 245 return f(self, *args, **kwargs)
245 finally: 246 finally:
246 release(self) 247 release(self)
247 return wrapper 248 return wrapper
248 return decorator 249 return decorator
249 250
250 251
251 def monkeypatch(klass, methodname=None): 252 def monkeypatch(klass, methodname=None):
252 """Decorator extending class with the decorated callable 253 """Decorator extending class with the decorated callable. This is basically
254 a syntactic sugar vs class assignment.
255
253 >>> class A: 256 >>> class A:
254 ... pass 257 ... pass
255 >>> @monkeypatch(A) 258 >>> @monkeypatch(A)
256 ... def meth(self): 259 ... def meth(self):
257 ... return 12 260 ... return 12
258 ... 261 ...
259 >>> a = A() 262 >>> a = A()
260 >>> a.meth() 263 >>> a.meth()
261 12 264 12
262 >>> @monkeypatch(A, 'foo') 265 >>> @monkeypatch(A, 'foo')
263 ... def meth(self): 266 ... def meth(self):
264 ... return 12 267 ... return 12
265 ... 268 ...
266 >>> a.foo() 269 >>> a.foo()
267 12 270 12
268 """ 271 """
269 def decorator(func): 272 def decorator(func):
270 try: 273 try:
271 name = methodname or func.__name__ 274 name = methodname or func.__name__
272 except AttributeError: 275 except AttributeError:
273 raise AttributeError('%s has no __name__ attribute: ' 276 raise AttributeError('%s has no __name__ attribute: '
274 'you should provide an explicit `methodname`' 277 'you should provide an explicit `methodname`'
275 % func) 278 % func)
276 if callable(func) and sys.version_info < (3, 0): 279 setattr(klass, name, func)
277 setattr(klass, name, method_type(func, None, klass))
278 else:
279 # likely a property
280 # this is quite borderline but usage already in the wild ...
281 setattr(klass, name, func)
282 return func 280 return func
283 return decorator 281 return decorator
OLDNEW
« no previous file with comments | « third_party/logilab/common/debugger.py ('k') | third_party/logilab/common/deprecation.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698