gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / wrapt / decorators.py @ 745
History | View | Annotate | Download (19.7 KB)
1 |
"""This module implements decorators for implementing other decorators
|
---|---|
2 |
as well as some commonly used decorators.
|
3 |
|
4 |
"""
|
5 |
|
6 |
import sys |
7 |
|
8 |
PY2 = sys.version_info[0] == 2 |
9 |
PY3 = sys.version_info[0] == 3 |
10 |
|
11 |
if PY3:
|
12 |
string_types = str,
|
13 |
|
14 |
import builtins |
15 |
exec_ = getattr(builtins, "exec") |
16 |
del builtins
|
17 |
|
18 |
else:
|
19 |
string_types = basestring,
|
20 |
|
21 |
def exec_(_code_, _globs_=None, _locs_=None): |
22 |
"""Execute code in a namespace."""
|
23 |
if _globs_ is None: |
24 |
frame = sys._getframe(1)
|
25 |
_globs_ = frame.f_globals |
26 |
if _locs_ is None: |
27 |
_locs_ = frame.f_locals |
28 |
del frame
|
29 |
elif _locs_ is None: |
30 |
_locs_ = _globs_ |
31 |
exec("""exec _code_ in _globs_, _locs_""")
|
32 |
|
33 |
from functools import partial |
34 |
from inspect import getargspec, ismethod, isclass, formatargspec |
35 |
from collections import namedtuple |
36 |
from threading import Lock, RLock |
37 |
|
38 |
try:
|
39 |
from inspect import signature |
40 |
except ImportError: |
41 |
pass
|
42 |
|
43 |
from .wrappers import (FunctionWrapper, BoundFunctionWrapper, ObjectProxy, |
44 |
CallableObjectProxy) |
45 |
|
46 |
# Adapter wrapper for the wrapped function which will overlay certain
|
47 |
# properties from the adapter function onto the wrapped function so that
|
48 |
# functions such as inspect.getargspec(), inspect.getfullargspec(),
|
49 |
# inspect.signature() and inspect.getsource() return the correct results
|
50 |
# one would expect.
|
51 |
|
52 |
class _AdapterFunctionCode(CallableObjectProxy): |
53 |
|
54 |
def __init__(self, wrapped_code, adapter_code): |
55 |
super(_AdapterFunctionCode, self).__init__(wrapped_code) |
56 |
self._self_adapter_code = adapter_code
|
57 |
|
58 |
@property
|
59 |
def co_argcount(self): |
60 |
return self._self_adapter_code.co_argcount |
61 |
|
62 |
@property
|
63 |
def co_code(self): |
64 |
return self._self_adapter_code.co_code |
65 |
|
66 |
@property
|
67 |
def co_flags(self): |
68 |
return self._self_adapter_code.co_flags |
69 |
|
70 |
@property
|
71 |
def co_kwonlyargcount(self): |
72 |
return self._self_adapter_code.co_kwonlyargcount |
73 |
|
74 |
@property
|
75 |
def co_varnames(self): |
76 |
return self._self_adapter_code.co_varnames |
77 |
|
78 |
class _AdapterFunctionSurrogate(CallableObjectProxy): |
79 |
|
80 |
def __init__(self, wrapped, adapter): |
81 |
super(_AdapterFunctionSurrogate, self).__init__(wrapped) |
82 |
self._self_adapter = adapter
|
83 |
|
84 |
@property
|
85 |
def __code__(self): |
86 |
return _AdapterFunctionCode(self.__wrapped__.__code__, |
87 |
self._self_adapter.__code__)
|
88 |
|
89 |
@property
|
90 |
def __defaults__(self): |
91 |
return self._self_adapter.__defaults__ |
92 |
|
93 |
@property
|
94 |
def __kwdefaults__(self): |
95 |
return self._self_adapter.__kwdefaults__ |
96 |
|
97 |
@property
|
98 |
def __signature__(self): |
99 |
if 'signature' not in globals(): |
100 |
return self._self_adapter.__signature__ |
101 |
else:
|
102 |
# Can't allow this to fail on Python 3 else it falls
|
103 |
# through to using __wrapped__, but that will be the
|
104 |
# wrong function we want to derive the signature
|
105 |
# from. Thus generate the signature ourselves.
|
106 |
|
107 |
return signature(self._self_adapter) |
108 |
|
109 |
if PY2:
|
110 |
func_code = __code__ |
111 |
func_defaults = __defaults__ |
112 |
|
113 |
class _BoundAdapterWrapper(BoundFunctionWrapper): |
114 |
|
115 |
@property
|
116 |
def __func__(self): |
117 |
return _AdapterFunctionSurrogate(self.__wrapped__.__func__, |
118 |
self._self_parent._self_adapter)
|
119 |
|
120 |
if PY2:
|
121 |
im_func = __func__ |
122 |
|
123 |
class AdapterWrapper(FunctionWrapper): |
124 |
|
125 |
__bound_function_wrapper__ = _BoundAdapterWrapper |
126 |
|
127 |
def __init__(self, *args, **kwargs): |
128 |
adapter = kwargs.pop('adapter')
|
129 |
super(AdapterWrapper, self).__init__(*args, **kwargs) |
130 |
self._self_surrogate = _AdapterFunctionSurrogate(
|
131 |
self.__wrapped__, adapter)
|
132 |
self._self_adapter = adapter
|
133 |
|
134 |
@property
|
135 |
def __code__(self): |
136 |
return self._self_surrogate.__code__ |
137 |
|
138 |
@property
|
139 |
def __defaults__(self): |
140 |
return self._self_surrogate.__defaults__ |
141 |
|
142 |
@property
|
143 |
def __kwdefaults__(self): |
144 |
return self._self_surrogate.__kwdefaults__ |
145 |
|
146 |
if PY2:
|
147 |
func_code = __code__ |
148 |
func_defaults = __defaults__ |
149 |
|
150 |
@property
|
151 |
def __signature__(self): |
152 |
return self._self_surrogate.__signature__ |
153 |
|
154 |
class AdapterFactory(object): |
155 |
def __call__(self, wrapped): |
156 |
raise NotImplementedError() |
157 |
|
158 |
class DelegatedAdapterFactory(AdapterFactory): |
159 |
def __init__(self, factory): |
160 |
super(DelegatedAdapterFactory, self).__init__() |
161 |
self.factory = factory
|
162 |
def __call__(self, wrapped): |
163 |
return self.factory(wrapped) |
164 |
|
165 |
adapter_factory = DelegatedAdapterFactory |
166 |
|
167 |
# Decorator for creating other decorators. This decorator and the
|
168 |
# wrappers which they use are designed to properly preserve any name
|
169 |
# attributes, function signatures etc, in addition to the wrappers
|
170 |
# themselves acting like a transparent proxy for the original wrapped
|
171 |
# function so the wrapper is effectively indistinguishable from the
|
172 |
# original wrapped function.
|
173 |
|
174 |
def decorator(wrapper=None, enabled=None, adapter=None): |
175 |
# The decorator should be supplied with a single positional argument
|
176 |
# which is the wrapper function to be used to implement the
|
177 |
# decorator. This may be preceded by a step whereby the keyword
|
178 |
# arguments are supplied to customise the behaviour of the
|
179 |
# decorator. The 'adapter' argument is used to optionally denote a
|
180 |
# separate function which is notionally used by an adapter
|
181 |
# decorator. In that case parts of the function '__code__' and
|
182 |
# '__defaults__' attributes are used from the adapter function
|
183 |
# rather than those of the wrapped function. This allows for the
|
184 |
# argument specification from inspect.getargspec() to be overridden
|
185 |
# with a prototype for a different function than what was wrapped.
|
186 |
# The 'enabled' argument provides a way to enable/disable the use
|
187 |
# of the decorator. If the type of 'enabled' is a boolean, then it
|
188 |
# is evaluated immediately and the wrapper not even applied if
|
189 |
# it is False. If not a boolean, it will be evaluated when the
|
190 |
# wrapper is called for an unbound wrapper, and when binding occurs
|
191 |
# for a bound wrapper. When being evaluated, if 'enabled' is callable
|
192 |
# it will be called to obtain the value to be checked. If False,
|
193 |
# the wrapper will not be called and instead the original wrapped
|
194 |
# function will be called directly instead.
|
195 |
|
196 |
if wrapper is not None: |
197 |
# Helper function for creating wrapper of the appropriate
|
198 |
# time when we need it down below.
|
199 |
|
200 |
def _build(wrapped, wrapper, enabled=None, adapter=None): |
201 |
if adapter:
|
202 |
if isinstance(adapter, AdapterFactory): |
203 |
adapter = adapter(wrapped) |
204 |
|
205 |
if not callable(adapter): |
206 |
ns = {} |
207 |
if not isinstance(adapter, string_types): |
208 |
adapter = formatargspec(*adapter) |
209 |
exec_('def adapter{0}: pass'.format(adapter), ns, ns)
|
210 |
adapter = ns['adapter']
|
211 |
|
212 |
return AdapterWrapper(wrapped=wrapped, wrapper=wrapper,
|
213 |
enabled=enabled, adapter=adapter) |
214 |
|
215 |
return FunctionWrapper(wrapped=wrapped, wrapper=wrapper,
|
216 |
enabled=enabled) |
217 |
|
218 |
# The wrapper has been provided so return the final decorator.
|
219 |
# The decorator is itself one of our function wrappers so we
|
220 |
# can determine when it is applied to functions, instance methods
|
221 |
# or class methods. This allows us to bind the instance or class
|
222 |
# method so the appropriate self or cls attribute is supplied
|
223 |
# when it is finally called.
|
224 |
|
225 |
def _wrapper(wrapped, instance, args, kwargs): |
226 |
# We first check for the case where the decorator was applied
|
227 |
# to a class type.
|
228 |
#
|
229 |
# @decorator
|
230 |
# class mydecoratorclass(object):
|
231 |
# def __init__(self, arg=None):
|
232 |
# self.arg = arg
|
233 |
# def __call__(self, wrapped, instance, args, kwargs):
|
234 |
# return wrapped(*args, **kwargs)
|
235 |
#
|
236 |
# @mydecoratorclass(arg=1)
|
237 |
# def function():
|
238 |
# pass
|
239 |
#
|
240 |
# In this case an instance of the class is to be used as the
|
241 |
# decorator wrapper function. If args was empty at this point,
|
242 |
# then it means that there were optional keyword arguments
|
243 |
# supplied to be used when creating an instance of the class
|
244 |
# to be used as the wrapper function.
|
245 |
|
246 |
if instance is None and isclass(wrapped) and not args: |
247 |
# We still need to be passed the target function to be
|
248 |
# wrapped as yet, so we need to return a further function
|
249 |
# to be able to capture it.
|
250 |
|
251 |
def _capture(target_wrapped): |
252 |
# Now have the target function to be wrapped and need
|
253 |
# to create an instance of the class which is to act
|
254 |
# as the decorator wrapper function. Before we do that,
|
255 |
# we need to first check that use of the decorator
|
256 |
# hadn't been disabled by a simple boolean. If it was,
|
257 |
# the target function to be wrapped is returned instead.
|
258 |
|
259 |
_enabled = enabled |
260 |
if type(_enabled) is bool: |
261 |
if not _enabled: |
262 |
return target_wrapped
|
263 |
_enabled = None
|
264 |
|
265 |
# Now create an instance of the class which is to act
|
266 |
# as the decorator wrapper function. Any arguments had
|
267 |
# to be supplied as keyword only arguments so that is
|
268 |
# all we pass when creating it.
|
269 |
|
270 |
target_wrapper = wrapped(**kwargs) |
271 |
|
272 |
# Finally build the wrapper itself and return it.
|
273 |
|
274 |
return _build(target_wrapped, target_wrapper,
|
275 |
_enabled, adapter) |
276 |
|
277 |
return _capture
|
278 |
|
279 |
# We should always have the target function to be wrapped at
|
280 |
# this point as the first (and only) value in args.
|
281 |
|
282 |
target_wrapped = args[0]
|
283 |
|
284 |
# Need to now check that use of the decorator hadn't been
|
285 |
# disabled by a simple boolean. If it was, then target
|
286 |
# function to be wrapped is returned instead.
|
287 |
|
288 |
_enabled = enabled |
289 |
if type(_enabled) is bool: |
290 |
if not _enabled: |
291 |
return target_wrapped
|
292 |
_enabled = None
|
293 |
|
294 |
# We now need to build the wrapper, but there are a couple of
|
295 |
# different cases we need to consider.
|
296 |
|
297 |
if instance is None: |
298 |
if isclass(wrapped):
|
299 |
# In this case the decorator was applied to a class
|
300 |
# type but optional keyword arguments were not supplied
|
301 |
# for initialising an instance of the class to be used
|
302 |
# as the decorator wrapper function.
|
303 |
#
|
304 |
# @decorator
|
305 |
# class mydecoratorclass(object):
|
306 |
# def __init__(self, arg=None):
|
307 |
# self.arg = arg
|
308 |
# def __call__(self, wrapped, instance,
|
309 |
# args, kwargs):
|
310 |
# return wrapped(*args, **kwargs)
|
311 |
#
|
312 |
# @mydecoratorclass
|
313 |
# def function():
|
314 |
# pass
|
315 |
#
|
316 |
# We still need to create an instance of the class to
|
317 |
# be used as the decorator wrapper function, but no
|
318 |
# arguments are pass.
|
319 |
|
320 |
target_wrapper = wrapped() |
321 |
|
322 |
else:
|
323 |
# In this case the decorator was applied to a normal
|
324 |
# function, or possibly a static method of a class.
|
325 |
#
|
326 |
# @decorator
|
327 |
# def mydecoratorfuntion(wrapped, instance,
|
328 |
# args, kwargs):
|
329 |
# return wrapped(*args, **kwargs)
|
330 |
#
|
331 |
# @mydecoratorfunction
|
332 |
# def function():
|
333 |
# pass
|
334 |
#
|
335 |
# That normal function becomes the decorator wrapper
|
336 |
# function.
|
337 |
|
338 |
target_wrapper = wrapper |
339 |
|
340 |
else:
|
341 |
if isclass(instance):
|
342 |
# In this case the decorator was applied to a class
|
343 |
# method.
|
344 |
#
|
345 |
# class myclass(object):
|
346 |
# @decorator
|
347 |
# @classmethod
|
348 |
# def decoratorclassmethod(cls, wrapped,
|
349 |
# instance, args, kwargs):
|
350 |
# return wrapped(*args, **kwargs)
|
351 |
#
|
352 |
# instance = myclass()
|
353 |
#
|
354 |
# @instance.decoratorclassmethod
|
355 |
# def function():
|
356 |
# pass
|
357 |
#
|
358 |
# This one is a bit strange because binding was actually
|
359 |
# performed on the wrapper created by our decorator
|
360 |
# factory. We need to apply that binding to the decorator
|
361 |
# wrapper function which which the decorator factory
|
362 |
# was applied to.
|
363 |
|
364 |
target_wrapper = wrapper.__get__(None, instance)
|
365 |
|
366 |
else:
|
367 |
# In this case the decorator was applied to an instance
|
368 |
# method.
|
369 |
#
|
370 |
# class myclass(object):
|
371 |
# @decorator
|
372 |
# def decoratorclassmethod(self, wrapped,
|
373 |
# instance, args, kwargs):
|
374 |
# return wrapped(*args, **kwargs)
|
375 |
#
|
376 |
# instance = myclass()
|
377 |
#
|
378 |
# @instance.decoratorclassmethod
|
379 |
# def function():
|
380 |
# pass
|
381 |
#
|
382 |
# This one is a bit strange because binding was actually
|
383 |
# performed on the wrapper created by our decorator
|
384 |
# factory. We need to apply that binding to the decorator
|
385 |
# wrapper function which which the decorator factory
|
386 |
# was applied to.
|
387 |
|
388 |
target_wrapper = wrapper.__get__(instance, type(instance))
|
389 |
|
390 |
# Finally build the wrapper itself and return it.
|
391 |
|
392 |
return _build(target_wrapped, target_wrapper, _enabled, adapter)
|
393 |
|
394 |
# We first return our magic function wrapper here so we can
|
395 |
# determine in what context the decorator factory was used. In
|
396 |
# other words, it is itself a universal decorator.
|
397 |
|
398 |
return _build(wrapper, _wrapper)
|
399 |
|
400 |
else:
|
401 |
# The wrapper still has not been provided, so we are just
|
402 |
# collecting the optional keyword arguments. Return the
|
403 |
# decorator again wrapped in a partial using the collected
|
404 |
# arguments.
|
405 |
|
406 |
return partial(decorator, enabled=enabled, adapter=adapter)
|
407 |
|
408 |
# Decorator for implementing thread synchronization. It can be used as a
|
409 |
# decorator, in which case the synchronization context is determined by
|
410 |
# what type of function is wrapped, or it can also be used as a context
|
411 |
# manager, where the user needs to supply the correct synchronization
|
412 |
# context. It is also possible to supply an object which appears to be a
|
413 |
# synchronization primitive of some sort, by virtue of having release()
|
414 |
# and acquire() methods. In that case that will be used directly as the
|
415 |
# synchronization primitive without creating a separate lock against the
|
416 |
# derived or supplied context.
|
417 |
|
418 |
def synchronized(wrapped): |
419 |
# Determine if being passed an object which is a synchronization
|
420 |
# primitive. We can't check by type for Lock, RLock, Semaphore etc,
|
421 |
# as the means of creating them isn't the type. Therefore use the
|
422 |
# existence of acquire() and release() methods. This is more
|
423 |
# extensible anyway as it allows custom synchronization mechanisms.
|
424 |
|
425 |
if hasattr(wrapped, 'acquire') and hasattr(wrapped, 'release'): |
426 |
# We remember what the original lock is and then return a new
|
427 |
# decorator which acceses and locks it. When returning the new
|
428 |
# decorator we wrap it with an object proxy so we can override
|
429 |
# the context manager methods in case it is being used to wrap
|
430 |
# synchronized statements with a 'with' statement.
|
431 |
|
432 |
lock = wrapped |
433 |
|
434 |
@decorator
|
435 |
def _synchronized(wrapped, instance, args, kwargs): |
436 |
# Execute the wrapped function while the original supplied
|
437 |
# lock is held.
|
438 |
|
439 |
with lock:
|
440 |
return wrapped(*args, **kwargs)
|
441 |
|
442 |
class _PartialDecorator(CallableObjectProxy): |
443 |
|
444 |
def __enter__(self): |
445 |
lock.acquire() |
446 |
return lock
|
447 |
|
448 |
def __exit__(self, *args): |
449 |
lock.release() |
450 |
|
451 |
return _PartialDecorator(wrapped=_synchronized)
|
452 |
|
453 |
# Following only apply when the lock is being created automatically
|
454 |
# based on the context of what was supplied. In this case we supply
|
455 |
# a final decorator, but need to use FunctionWrapper directly as we
|
456 |
# want to derive from it to add context manager methods in in case it is
|
457 |
# being used to wrap synchronized statements with a 'with' statement.
|
458 |
|
459 |
def _synchronized_lock(context): |
460 |
# Attempt to retrieve the lock for the specific context.
|
461 |
|
462 |
lock = vars(context).get('_synchronized_lock', None) |
463 |
|
464 |
if lock is None: |
465 |
# There is no existing lock defined for the context we
|
466 |
# are dealing with so we need to create one. This needs
|
467 |
# to be done in a way to guarantee there is only one
|
468 |
# created, even if multiple threads try and create it at
|
469 |
# the same time. We can't always use the setdefault()
|
470 |
# method on the __dict__ for the context. This is the
|
471 |
# case where the context is a class, as __dict__ is
|
472 |
# actually a dictproxy. What we therefore do is use a
|
473 |
# meta lock on this wrapper itself, to control the
|
474 |
# creation and assignment of the lock attribute against
|
475 |
# the context.
|
476 |
|
477 |
meta_lock = vars(synchronized).setdefault(
|
478 |
'_synchronized_meta_lock', Lock())
|
479 |
|
480 |
with meta_lock:
|
481 |
# We need to check again for whether the lock we want
|
482 |
# exists in case two threads were trying to create it
|
483 |
# at the same time and were competing to create the
|
484 |
# meta lock.
|
485 |
|
486 |
lock = vars(context).get('_synchronized_lock', None) |
487 |
|
488 |
if lock is None: |
489 |
lock = RLock() |
490 |
setattr(context, '_synchronized_lock', lock) |
491 |
|
492 |
return lock
|
493 |
|
494 |
def _synchronized_wrapper(wrapped, instance, args, kwargs): |
495 |
# Execute the wrapped function while the lock for the
|
496 |
# desired context is held. If instance is None then the
|
497 |
# wrapped function is used as the context.
|
498 |
|
499 |
with _synchronized_lock(instance or wrapped): |
500 |
return wrapped(*args, **kwargs)
|
501 |
|
502 |
class _FinalDecorator(FunctionWrapper): |
503 |
|
504 |
def __enter__(self): |
505 |
self._self_lock = _synchronized_lock(self.__wrapped__) |
506 |
self._self_lock.acquire()
|
507 |
return self._self_lock |
508 |
|
509 |
def __exit__(self, *args): |
510 |
self._self_lock.release()
|
511 |
|
512 |
return _FinalDecorator(wrapped=wrapped, wrapper=_synchronized_wrapper)
|