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

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

Issue 719313003: Revert "pylint: upgrade to 1.3.1" (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years, 1 month 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
« 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-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 1 # copyright 2003-2011 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
22 __docformat__ = "restructuredtext en" 19 __docformat__ = "restructuredtext en"
23 20
24 import sys 21 import sys
25 import types
26 from time import clock, time 22 from time import clock, time
27 from inspect import isgeneratorfunction, getargspec
28 23
29 from logilab.common.compat import method_type 24 from logilab.common.compat import callable, method_type
30 25
31 # XXX rewrite so we can use the decorator syntax when keyarg has to be specified 26 # XXX rewrite so we can use the decorator syntax when keyarg has to be specified
32 27
28 def _is_generator_function(callableobj):
29 return callableobj.func_code.co_flags & 0x20
30
33 class cached_decorator(object): 31 class cached_decorator(object):
34 def __init__(self, cacheattr=None, keyarg=None): 32 def __init__(self, cacheattr=None, keyarg=None):
35 self.cacheattr = cacheattr 33 self.cacheattr = cacheattr
36 self.keyarg = keyarg 34 self.keyarg = keyarg
37 def __call__(self, callableobj=None): 35 def __call__(self, callableobj=None):
38 assert not isgeneratorfunction(callableobj), \ 36 assert not _is_generator_function(callableobj), \
39 'cannot cache generator function: %s' % callableobj 37 'cannot cache generator function: %s' % callableobj
40 if len(getargspec(callableobj).args) == 1 or self.keyarg == 0: 38 if callableobj.func_code.co_argcount == 1 or self.keyarg == 0:
41 cache = _SingleValueCache(callableobj, self.cacheattr) 39 cache = _SingleValueCache(callableobj, self.cacheattr)
42 elif self.keyarg: 40 elif self.keyarg:
43 cache = _MultiValuesKeyArgCache(callableobj, self.keyarg, self.cache attr) 41 cache = _MultiValuesKeyArgCache(callableobj, self.keyarg, self.cache attr)
44 else: 42 else:
45 cache = _MultiValuesCache(callableobj, self.cacheattr) 43 cache = _MultiValuesCache(callableobj, self.cacheattr)
46 return cache.closure() 44 return cache.closure()
47 45
48 class _SingleValueCache(object): 46 class _SingleValueCache(object):
49 def __init__(self, callableobj, cacheattr=None): 47 def __init__(self, callableobj, cacheattr=None):
50 self.callable = callableobj 48 self.callable = callableobj
(...skipping 11 matching lines...) Expand all
62 setattr(self, __me.cacheattr, value) 60 setattr(self, __me.cacheattr, value)
63 return value 61 return value
64 62
65 def closure(self): 63 def closure(self):
66 def wrapped(*args, **kwargs): 64 def wrapped(*args, **kwargs):
67 return self.__call__(*args, **kwargs) 65 return self.__call__(*args, **kwargs)
68 wrapped.cache_obj = self 66 wrapped.cache_obj = self
69 try: 67 try:
70 wrapped.__doc__ = self.callable.__doc__ 68 wrapped.__doc__ = self.callable.__doc__
71 wrapped.__name__ = self.callable.__name__ 69 wrapped.__name__ = self.callable.__name__
70 wrapped.func_name = self.callable.func_name
72 except: 71 except:
73 pass 72 pass
74 return wrapped 73 return wrapped
75 74
76 def clear(self, holder): 75 def clear(self, holder):
77 holder.__dict__.pop(self.cacheattr, None) 76 holder.__dict__.pop(self.cacheattr, None)
78 77
79 78
80 class _MultiValuesCache(_SingleValueCache): 79 class _MultiValuesCache(_SingleValueCache):
81 def _get_cache(self, holder): 80 def _get_cache(self, holder):
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 return method_type(self.func, instance, objtype) 219 return method_type(self.func, instance, objtype)
221 def __set__(self, instance, value): 220 def __set__(self, instance, value):
222 raise AttributeError("can't set attribute") 221 raise AttributeError("can't set attribute")
223 222
224 223
225 def timed(f): 224 def timed(f):
226 def wrap(*args, **kwargs): 225 def wrap(*args, **kwargs):
227 t = time() 226 t = time()
228 c = clock() 227 c = clock()
229 res = f(*args, **kwargs) 228 res = f(*args, **kwargs)
230 print('%s clock: %.9f / time: %.9f' % (f.__name__, 229 print '%s clock: %.9f / time: %.9f' % (f.__name__,
231 clock() - c, time() - t)) 230 clock() - c, time() - t)
232 return res 231 return res
233 return wrap 232 return wrap
234 233
235 234
236 def locked(acquire, release): 235 def locked(acquire, release):
237 """Decorator taking two methods to acquire/release a lock as argument, 236 """Decorator taking two methods to acquire/release a lock as argument,
238 returning a decorator function which will call the inner method after 237 returning a decorator function which will call the inner method after
239 having called acquire(self) et will call release(self) afterwards. 238 having called acquire(self) et will call release(self) afterwards.
240 """ 239 """
241 def decorator(f): 240 def decorator(f):
242 def wrapper(self, *args, **kwargs): 241 def wrapper(self, *args, **kwargs):
243 acquire(self) 242 acquire(self)
244 try: 243 try:
245 return f(self, *args, **kwargs) 244 return f(self, *args, **kwargs)
246 finally: 245 finally:
247 release(self) 246 release(self)
248 return wrapper 247 return wrapper
249 return decorator 248 return decorator
250 249
251 250
252 def monkeypatch(klass, methodname=None): 251 def monkeypatch(klass, methodname=None):
253 """Decorator extending class with the decorated callable. This is basically 252 """Decorator extending class with the decorated callable
254 a syntactic sugar vs class assignment.
255
256 >>> class A: 253 >>> class A:
257 ... pass 254 ... pass
258 >>> @monkeypatch(A) 255 >>> @monkeypatch(A)
259 ... def meth(self): 256 ... def meth(self):
260 ... return 12 257 ... return 12
261 ... 258 ...
262 >>> a = A() 259 >>> a = A()
263 >>> a.meth() 260 >>> a.meth()
264 12 261 12
265 >>> @monkeypatch(A, 'foo') 262 >>> @monkeypatch(A, 'foo')
266 ... def meth(self): 263 ... def meth(self):
267 ... return 12 264 ... return 12
268 ... 265 ...
269 >>> a.foo() 266 >>> a.foo()
270 12 267 12
271 """ 268 """
272 def decorator(func): 269 def decorator(func):
273 try: 270 try:
274 name = methodname or func.__name__ 271 name = methodname or func.__name__
275 except AttributeError: 272 except AttributeError:
276 raise AttributeError('%s has no __name__ attribute: ' 273 raise AttributeError('%s has no __name__ attribute: '
277 'you should provide an explicit `methodname`' 274 'you should provide an explicit `methodname`'
278 % func) 275 % func)
279 setattr(klass, name, func) 276 if callable(func) and sys.version_info < (3, 0):
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)
280 return func 282 return func
281 return decorator 283 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