Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/decorator.py @ 0:d30785e31577 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author | guerler |
---|---|
date | Fri, 31 Jul 2020 00:18:57 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d30785e31577 |
---|---|
1 # ######################### LICENSE ############################ # | |
2 | |
3 # Copyright (c) 2005-2018, Michele Simionato | |
4 # All rights reserved. | |
5 | |
6 # Redistribution and use in source and binary forms, with or without | |
7 # modification, are permitted provided that the following conditions are | |
8 # met: | |
9 | |
10 # Redistributions of source code must retain the above copyright | |
11 # notice, this list of conditions and the following disclaimer. | |
12 # Redistributions in bytecode form must reproduce the above copyright | |
13 # notice, this list of conditions and the following disclaimer in | |
14 # the documentation and/or other materials provided with the | |
15 # distribution. | |
16 | |
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
21 # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
23 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | |
24 # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |
26 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | |
27 # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
28 # DAMAGE. | |
29 | |
30 """ | |
31 Decorator module, see http://pypi.python.org/pypi/decorator | |
32 for the documentation. | |
33 """ | |
34 from __future__ import print_function | |
35 | |
36 import re | |
37 import sys | |
38 import inspect | |
39 import operator | |
40 import itertools | |
41 import collections | |
42 | |
43 __version__ = '4.4.2' | |
44 | |
45 if sys.version_info >= (3,): | |
46 from inspect import getfullargspec | |
47 | |
48 def get_init(cls): | |
49 return cls.__init__ | |
50 else: | |
51 FullArgSpec = collections.namedtuple( | |
52 'FullArgSpec', 'args varargs varkw defaults ' | |
53 'kwonlyargs kwonlydefaults annotations') | |
54 | |
55 def getfullargspec(f): | |
56 "A quick and dirty replacement for getfullargspec for Python 2.X" | |
57 return FullArgSpec._make(inspect.getargspec(f) + ([], None, {})) | |
58 | |
59 def get_init(cls): | |
60 return cls.__init__.__func__ | |
61 | |
62 try: | |
63 iscoroutinefunction = inspect.iscoroutinefunction | |
64 except AttributeError: | |
65 # let's assume there are no coroutine functions in old Python | |
66 def iscoroutinefunction(f): | |
67 return False | |
68 try: | |
69 from inspect import isgeneratorfunction | |
70 except ImportError: | |
71 # assume no generator function in old Python versions | |
72 def isgeneratorfunction(caller): | |
73 return False | |
74 | |
75 | |
76 DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(') | |
77 | |
78 | |
79 # basic functionality | |
80 class FunctionMaker(object): | |
81 """ | |
82 An object with the ability to create functions with a given signature. | |
83 It has attributes name, doc, module, signature, defaults, dict and | |
84 methods update and make. | |
85 """ | |
86 | |
87 # Atomic get-and-increment provided by the GIL | |
88 _compile_count = itertools.count() | |
89 | |
90 # make pylint happy | |
91 args = varargs = varkw = defaults = kwonlyargs = kwonlydefaults = () | |
92 | |
93 def __init__(self, func=None, name=None, signature=None, | |
94 defaults=None, doc=None, module=None, funcdict=None): | |
95 self.shortsignature = signature | |
96 if func: | |
97 # func can be a class or a callable, but not an instance method | |
98 self.name = func.__name__ | |
99 if self.name == '<lambda>': # small hack for lambda functions | |
100 self.name = '_lambda_' | |
101 self.doc = func.__doc__ | |
102 self.module = func.__module__ | |
103 if inspect.isfunction(func): | |
104 argspec = getfullargspec(func) | |
105 self.annotations = getattr(func, '__annotations__', {}) | |
106 for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs', | |
107 'kwonlydefaults'): | |
108 setattr(self, a, getattr(argspec, a)) | |
109 for i, arg in enumerate(self.args): | |
110 setattr(self, 'arg%d' % i, arg) | |
111 allargs = list(self.args) | |
112 allshortargs = list(self.args) | |
113 if self.varargs: | |
114 allargs.append('*' + self.varargs) | |
115 allshortargs.append('*' + self.varargs) | |
116 elif self.kwonlyargs: | |
117 allargs.append('*') # single star syntax | |
118 for a in self.kwonlyargs: | |
119 allargs.append('%s=None' % a) | |
120 allshortargs.append('%s=%s' % (a, a)) | |
121 if self.varkw: | |
122 allargs.append('**' + self.varkw) | |
123 allshortargs.append('**' + self.varkw) | |
124 self.signature = ', '.join(allargs) | |
125 self.shortsignature = ', '.join(allshortargs) | |
126 self.dict = func.__dict__.copy() | |
127 # func=None happens when decorating a caller | |
128 if name: | |
129 self.name = name | |
130 if signature is not None: | |
131 self.signature = signature | |
132 if defaults: | |
133 self.defaults = defaults | |
134 if doc: | |
135 self.doc = doc | |
136 if module: | |
137 self.module = module | |
138 if funcdict: | |
139 self.dict = funcdict | |
140 # check existence required attributes | |
141 assert hasattr(self, 'name') | |
142 if not hasattr(self, 'signature'): | |
143 raise TypeError('You are decorating a non function: %s' % func) | |
144 | |
145 def update(self, func, **kw): | |
146 "Update the signature of func with the data in self" | |
147 func.__name__ = self.name | |
148 func.__doc__ = getattr(self, 'doc', None) | |
149 func.__dict__ = getattr(self, 'dict', {}) | |
150 func.__defaults__ = self.defaults | |
151 func.__kwdefaults__ = self.kwonlydefaults or None | |
152 func.__annotations__ = getattr(self, 'annotations', None) | |
153 try: | |
154 frame = sys._getframe(3) | |
155 except AttributeError: # for IronPython and similar implementations | |
156 callermodule = '?' | |
157 else: | |
158 callermodule = frame.f_globals.get('__name__', '?') | |
159 func.__module__ = getattr(self, 'module', callermodule) | |
160 func.__dict__.update(kw) | |
161 | |
162 def make(self, src_templ, evaldict=None, addsource=False, **attrs): | |
163 "Make a new function from a given template and update the signature" | |
164 src = src_templ % vars(self) # expand name and signature | |
165 evaldict = evaldict or {} | |
166 mo = DEF.search(src) | |
167 if mo is None: | |
168 raise SyntaxError('not a valid function template\n%s' % src) | |
169 name = mo.group(1) # extract the function name | |
170 names = set([name] + [arg.strip(' *') for arg in | |
171 self.shortsignature.split(',')]) | |
172 for n in names: | |
173 if n in ('_func_', '_call_'): | |
174 raise NameError('%s is overridden in\n%s' % (n, src)) | |
175 | |
176 if not src.endswith('\n'): # add a newline for old Pythons | |
177 src += '\n' | |
178 | |
179 # Ensure each generated function has a unique filename for profilers | |
180 # (such as cProfile) that depend on the tuple of (<filename>, | |
181 # <definition line>, <function name>) being unique. | |
182 filename = '<decorator-gen-%d>' % next(self._compile_count) | |
183 try: | |
184 code = compile(src, filename, 'single') | |
185 exec(code, evaldict) | |
186 except Exception: | |
187 print('Error in generated code:', file=sys.stderr) | |
188 print(src, file=sys.stderr) | |
189 raise | |
190 func = evaldict[name] | |
191 if addsource: | |
192 attrs['__source__'] = src | |
193 self.update(func, **attrs) | |
194 return func | |
195 | |
196 @classmethod | |
197 def create(cls, obj, body, evaldict, defaults=None, | |
198 doc=None, module=None, addsource=True, **attrs): | |
199 """ | |
200 Create a function from the strings name, signature and body. | |
201 evaldict is the evaluation dictionary. If addsource is true an | |
202 attribute __source__ is added to the result. The attributes attrs | |
203 are added, if any. | |
204 """ | |
205 if isinstance(obj, str): # "name(signature)" | |
206 name, rest = obj.strip().split('(', 1) | |
207 signature = rest[:-1] # strip a right parens | |
208 func = None | |
209 else: # a function | |
210 name = None | |
211 signature = None | |
212 func = obj | |
213 self = cls(func, name, signature, defaults, doc, module) | |
214 ibody = '\n'.join(' ' + line for line in body.splitlines()) | |
215 caller = evaldict.get('_call_') # when called from `decorate` | |
216 if caller and iscoroutinefunction(caller): | |
217 body = ('async def %(name)s(%(signature)s):\n' + ibody).replace( | |
218 'return', 'return await') | |
219 else: | |
220 body = 'def %(name)s(%(signature)s):\n' + ibody | |
221 return self.make(body, evaldict, addsource, **attrs) | |
222 | |
223 | |
224 def decorate(func, caller, extras=()): | |
225 """ | |
226 decorate(func, caller) decorates a function using a caller. | |
227 If the caller is a generator function, the resulting function | |
228 will be a generator function. | |
229 """ | |
230 evaldict = dict(_call_=caller, _func_=func) | |
231 es = '' | |
232 for i, extra in enumerate(extras): | |
233 ex = '_e%d_' % i | |
234 evaldict[ex] = extra | |
235 es += ex + ', ' | |
236 | |
237 if '3.5' <= sys.version < '3.6': | |
238 # with Python 3.5 isgeneratorfunction returns True for all coroutines | |
239 # however we know that it is NOT possible to have a generator | |
240 # coroutine in python 3.5: PEP525 was not there yet | |
241 generatorcaller = isgeneratorfunction( | |
242 caller) and not iscoroutinefunction(caller) | |
243 else: | |
244 generatorcaller = isgeneratorfunction(caller) | |
245 if generatorcaller: | |
246 fun = FunctionMaker.create( | |
247 func, "for res in _call_(_func_, %s%%(shortsignature)s):\n" | |
248 " yield res" % es, evaldict, __wrapped__=func) | |
249 else: | |
250 fun = FunctionMaker.create( | |
251 func, "return _call_(_func_, %s%%(shortsignature)s)" % es, | |
252 evaldict, __wrapped__=func) | |
253 if hasattr(func, '__qualname__'): | |
254 fun.__qualname__ = func.__qualname__ | |
255 return fun | |
256 | |
257 | |
258 def decorator(caller, _func=None): | |
259 """decorator(caller) converts a caller function into a decorator""" | |
260 if _func is not None: # return a decorated function | |
261 # this is obsolete behavior; you should use decorate instead | |
262 return decorate(_func, caller) | |
263 # else return a decorator function | |
264 defaultargs, defaults = '', () | |
265 if inspect.isclass(caller): | |
266 name = caller.__name__.lower() | |
267 doc = 'decorator(%s) converts functions/generators into ' \ | |
268 'factories of %s objects' % (caller.__name__, caller.__name__) | |
269 elif inspect.isfunction(caller): | |
270 if caller.__name__ == '<lambda>': | |
271 name = '_lambda_' | |
272 else: | |
273 name = caller.__name__ | |
274 doc = caller.__doc__ | |
275 nargs = caller.__code__.co_argcount | |
276 ndefs = len(caller.__defaults__ or ()) | |
277 defaultargs = ', '.join(caller.__code__.co_varnames[nargs-ndefs:nargs]) | |
278 if defaultargs: | |
279 defaultargs += ',' | |
280 defaults = caller.__defaults__ | |
281 else: # assume caller is an object with a __call__ method | |
282 name = caller.__class__.__name__.lower() | |
283 doc = caller.__call__.__doc__ | |
284 evaldict = dict(_call=caller, _decorate_=decorate) | |
285 dec = FunctionMaker.create( | |
286 '%s(func, %s)' % (name, defaultargs), | |
287 'if func is None: return lambda func: _decorate_(func, _call, (%s))\n' | |
288 'return _decorate_(func, _call, (%s))' % (defaultargs, defaultargs), | |
289 evaldict, doc=doc, module=caller.__module__, __wrapped__=caller) | |
290 if defaults: | |
291 dec.__defaults__ = (None,) + defaults | |
292 return dec | |
293 | |
294 | |
295 # ####################### contextmanager ####################### # | |
296 | |
297 try: # Python >= 3.2 | |
298 from contextlib import _GeneratorContextManager | |
299 except ImportError: # Python >= 2.5 | |
300 from contextlib import GeneratorContextManager as _GeneratorContextManager | |
301 | |
302 | |
303 class ContextManager(_GeneratorContextManager): | |
304 def __call__(self, func): | |
305 """Context manager decorator""" | |
306 return FunctionMaker.create( | |
307 func, "with _self_: return _func_(%(shortsignature)s)", | |
308 dict(_self_=self, _func_=func), __wrapped__=func) | |
309 | |
310 | |
311 init = getfullargspec(_GeneratorContextManager.__init__) | |
312 n_args = len(init.args) | |
313 if n_args == 2 and not init.varargs: # (self, genobj) Python 2.7 | |
314 def __init__(self, g, *a, **k): | |
315 return _GeneratorContextManager.__init__(self, g(*a, **k)) | |
316 ContextManager.__init__ = __init__ | |
317 elif n_args == 2 and init.varargs: # (self, gen, *a, **k) Python 3.4 | |
318 pass | |
319 elif n_args == 4: # (self, gen, args, kwds) Python 3.5 | |
320 def __init__(self, g, *a, **k): | |
321 return _GeneratorContextManager.__init__(self, g, a, k) | |
322 ContextManager.__init__ = __init__ | |
323 | |
324 _contextmanager = decorator(ContextManager) | |
325 | |
326 | |
327 def contextmanager(func): | |
328 # Enable Pylint config: contextmanager-decorators=decorator.contextmanager | |
329 return _contextmanager(func) | |
330 | |
331 | |
332 # ############################ dispatch_on ############################ # | |
333 | |
334 def append(a, vancestors): | |
335 """ | |
336 Append ``a`` to the list of the virtual ancestors, unless it is already | |
337 included. | |
338 """ | |
339 add = True | |
340 for j, va in enumerate(vancestors): | |
341 if issubclass(va, a): | |
342 add = False | |
343 break | |
344 if issubclass(a, va): | |
345 vancestors[j] = a | |
346 add = False | |
347 if add: | |
348 vancestors.append(a) | |
349 | |
350 | |
351 # inspired from simplegeneric by P.J. Eby and functools.singledispatch | |
352 def dispatch_on(*dispatch_args): | |
353 """ | |
354 Factory of decorators turning a function into a generic function | |
355 dispatching on the given arguments. | |
356 """ | |
357 assert dispatch_args, 'No dispatch args passed' | |
358 dispatch_str = '(%s,)' % ', '.join(dispatch_args) | |
359 | |
360 def check(arguments, wrong=operator.ne, msg=''): | |
361 """Make sure one passes the expected number of arguments""" | |
362 if wrong(len(arguments), len(dispatch_args)): | |
363 raise TypeError('Expected %d arguments, got %d%s' % | |
364 (len(dispatch_args), len(arguments), msg)) | |
365 | |
366 def gen_func_dec(func): | |
367 """Decorator turning a function into a generic function""" | |
368 | |
369 # first check the dispatch arguments | |
370 argset = set(getfullargspec(func).args) | |
371 if not set(dispatch_args) <= argset: | |
372 raise NameError('Unknown dispatch arguments %s' % dispatch_str) | |
373 | |
374 typemap = {} | |
375 | |
376 def vancestors(*types): | |
377 """ | |
378 Get a list of sets of virtual ancestors for the given types | |
379 """ | |
380 check(types) | |
381 ras = [[] for _ in range(len(dispatch_args))] | |
382 for types_ in typemap: | |
383 for t, type_, ra in zip(types, types_, ras): | |
384 if issubclass(t, type_) and type_ not in t.mro(): | |
385 append(type_, ra) | |
386 return [set(ra) for ra in ras] | |
387 | |
388 def ancestors(*types): | |
389 """ | |
390 Get a list of virtual MROs, one for each type | |
391 """ | |
392 check(types) | |
393 lists = [] | |
394 for t, vas in zip(types, vancestors(*types)): | |
395 n_vas = len(vas) | |
396 if n_vas > 1: | |
397 raise RuntimeError( | |
398 'Ambiguous dispatch for %s: %s' % (t, vas)) | |
399 elif n_vas == 1: | |
400 va, = vas | |
401 mro = type('t', (t, va), {}).mro()[1:] | |
402 else: | |
403 mro = t.mro() | |
404 lists.append(mro[:-1]) # discard t and object | |
405 return lists | |
406 | |
407 def register(*types): | |
408 """ | |
409 Decorator to register an implementation for the given types | |
410 """ | |
411 check(types) | |
412 | |
413 def dec(f): | |
414 check(getfullargspec(f).args, operator.lt, ' in ' + f.__name__) | |
415 typemap[types] = f | |
416 return f | |
417 return dec | |
418 | |
419 def dispatch_info(*types): | |
420 """ | |
421 An utility to introspect the dispatch algorithm | |
422 """ | |
423 check(types) | |
424 lst = [] | |
425 for anc in itertools.product(*ancestors(*types)): | |
426 lst.append(tuple(a.__name__ for a in anc)) | |
427 return lst | |
428 | |
429 def _dispatch(dispatch_args, *args, **kw): | |
430 types = tuple(type(arg) for arg in dispatch_args) | |
431 try: # fast path | |
432 f = typemap[types] | |
433 except KeyError: | |
434 pass | |
435 else: | |
436 return f(*args, **kw) | |
437 combinations = itertools.product(*ancestors(*types)) | |
438 next(combinations) # the first one has been already tried | |
439 for types_ in combinations: | |
440 f = typemap.get(types_) | |
441 if f is not None: | |
442 return f(*args, **kw) | |
443 | |
444 # else call the default implementation | |
445 return func(*args, **kw) | |
446 | |
447 return FunctionMaker.create( | |
448 func, 'return _f_(%s, %%(shortsignature)s)' % dispatch_str, | |
449 dict(_f_=_dispatch), register=register, default=func, | |
450 typemap=typemap, vancestors=vancestors, ancestors=ancestors, | |
451 dispatch_info=dispatch_info, __wrapped__=func) | |
452 | |
453 gen_func_dec.__name__ = 'dispatch_on' + dispatch_str | |
454 return gen_func_dec |