mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-07-05 20:51:11 -07:00
Updated decorator to 4.4.2
This commit is contained in:
parent
fb6011f88d
commit
5e3641ac23
1 changed files with 120 additions and 117 deletions
|
@ -1,6 +1,6 @@
|
|||
# ######################### LICENSE ############################ #
|
||||
|
||||
# Copyright (c) 2005-2021, Michele Simionato
|
||||
# Copyright (c) 2005-2018, Michele Simionato
|
||||
# All rights reserved.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
@ -28,26 +28,55 @@
|
|||
# DAMAGE.
|
||||
|
||||
"""
|
||||
Decorator module, see
|
||||
https://github.com/micheles/decorator/blob/master/docs/documentation.md
|
||||
Decorator module, see http://pypi.python.org/pypi/decorator
|
||||
for the documentation.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import re
|
||||
import sys
|
||||
import inspect
|
||||
import operator
|
||||
import itertools
|
||||
from contextlib import _GeneratorContextManager
|
||||
from inspect import getfullargspec, iscoroutinefunction, isgeneratorfunction
|
||||
import collections
|
||||
|
||||
__version__ = '4.4.2'
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
from inspect import getfullargspec
|
||||
|
||||
def get_init(cls):
|
||||
return cls.__init__
|
||||
else:
|
||||
FullArgSpec = collections.namedtuple(
|
||||
'FullArgSpec', 'args varargs varkw defaults '
|
||||
'kwonlyargs kwonlydefaults annotations')
|
||||
|
||||
def getfullargspec(f):
|
||||
"A quick and dirty replacement for getfullargspec for Python 2.X"
|
||||
return FullArgSpec._make(inspect.getargspec(f) + ([], None, {}))
|
||||
|
||||
def get_init(cls):
|
||||
return cls.__init__.__func__
|
||||
|
||||
try:
|
||||
iscoroutinefunction = inspect.iscoroutinefunction
|
||||
except AttributeError:
|
||||
# let's assume there are no coroutine functions in old Python
|
||||
def iscoroutinefunction(f):
|
||||
return False
|
||||
try:
|
||||
from inspect import isgeneratorfunction
|
||||
except ImportError:
|
||||
# assume no generator function in old Python versions
|
||||
def isgeneratorfunction(caller):
|
||||
return False
|
||||
|
||||
__version__ = '5.1.1'
|
||||
|
||||
DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(')
|
||||
POS = inspect.Parameter.POSITIONAL_OR_KEYWORD
|
||||
EMPTY = inspect.Parameter.empty
|
||||
|
||||
|
||||
# this is not used anymore in the core, but kept for backward compatibility
|
||||
# basic functionality
|
||||
class FunctionMaker(object):
|
||||
"""
|
||||
An object with the ability to create functions with a given signature.
|
||||
|
@ -71,7 +100,7 @@ class FunctionMaker(object):
|
|||
self.name = '_lambda_'
|
||||
self.doc = func.__doc__
|
||||
self.module = func.__module__
|
||||
if inspect.isroutine(func):
|
||||
if inspect.isfunction(func):
|
||||
argspec = getfullargspec(func)
|
||||
self.annotations = getattr(func, '__annotations__', {})
|
||||
for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs',
|
||||
|
@ -114,9 +143,7 @@ class FunctionMaker(object):
|
|||
raise TypeError('You are decorating a non function: %s' % func)
|
||||
|
||||
def update(self, func, **kw):
|
||||
"""
|
||||
Update the signature of func with the data in self
|
||||
"""
|
||||
"Update the signature of func with the data in self"
|
||||
func.__name__ = self.name
|
||||
func.__doc__ = getattr(self, 'doc', None)
|
||||
func.__dict__ = getattr(self, 'dict', {})
|
||||
|
@ -133,9 +160,7 @@ class FunctionMaker(object):
|
|||
func.__dict__.update(kw)
|
||||
|
||||
def make(self, src_templ, evaldict=None, addsource=False, **attrs):
|
||||
"""
|
||||
Make a new function from a given template and update the signature
|
||||
"""
|
||||
"Make a new function from a given template and update the signature"
|
||||
src = src_templ % vars(self) # expand name and signature
|
||||
evaldict = evaldict or {}
|
||||
mo = DEF.search(src)
|
||||
|
@ -196,128 +221,106 @@ class FunctionMaker(object):
|
|||
return self.make(body, evaldict, addsource, **attrs)
|
||||
|
||||
|
||||
def fix(args, kwargs, sig):
|
||||
def decorate(func, caller, extras=()):
|
||||
"""
|
||||
Fix args and kwargs to be consistent with the signature
|
||||
decorate(func, caller) decorates a function using a caller.
|
||||
If the caller is a generator function, the resulting function
|
||||
will be a generator function.
|
||||
"""
|
||||
ba = sig.bind(*args, **kwargs)
|
||||
ba.apply_defaults() # needed for test_dan_schult
|
||||
return ba.args, ba.kwargs
|
||||
evaldict = dict(_call_=caller, _func_=func)
|
||||
es = ''
|
||||
for i, extra in enumerate(extras):
|
||||
ex = '_e%d_' % i
|
||||
evaldict[ex] = extra
|
||||
es += ex + ', '
|
||||
|
||||
|
||||
def decorate(func, caller, extras=(), kwsyntax=False):
|
||||
"""
|
||||
Decorates a function/generator/coroutine using a caller.
|
||||
If kwsyntax is True calling the decorated functions with keyword
|
||||
syntax will pass the named arguments inside the ``kw`` dictionary,
|
||||
even if such argument are positional, similarly to what functools.wraps
|
||||
does. By default kwsyntax is False and the the arguments are untouched.
|
||||
"""
|
||||
sig = inspect.signature(func)
|
||||
if iscoroutinefunction(caller):
|
||||
async def fun(*args, **kw):
|
||||
if not kwsyntax:
|
||||
args, kw = fix(args, kw, sig)
|
||||
return await caller(func, *(extras + args), **kw)
|
||||
elif isgeneratorfunction(caller):
|
||||
def fun(*args, **kw):
|
||||
if not kwsyntax:
|
||||
args, kw = fix(args, kw, sig)
|
||||
for res in caller(func, *(extras + args), **kw):
|
||||
yield res
|
||||
if '3.5' <= sys.version < '3.6':
|
||||
# with Python 3.5 isgeneratorfunction returns True for all coroutines
|
||||
# however we know that it is NOT possible to have a generator
|
||||
# coroutine in python 3.5: PEP525 was not there yet
|
||||
generatorcaller = isgeneratorfunction(
|
||||
caller) and not iscoroutinefunction(caller)
|
||||
else:
|
||||
def fun(*args, **kw):
|
||||
if not kwsyntax:
|
||||
args, kw = fix(args, kw, sig)
|
||||
return caller(func, *(extras + args), **kw)
|
||||
fun.__name__ = func.__name__
|
||||
fun.__doc__ = func.__doc__
|
||||
fun.__wrapped__ = func
|
||||
fun.__signature__ = sig
|
||||
fun.__qualname__ = func.__qualname__
|
||||
# builtin functions like defaultdict.__setitem__ lack many attributes
|
||||
try:
|
||||
fun.__defaults__ = func.__defaults__
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
fun.__kwdefaults__ = func.__kwdefaults__
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
fun.__annotations__ = func.__annotations__
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
fun.__module__ = func.__module__
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
fun.__dict__.update(func.__dict__)
|
||||
except AttributeError:
|
||||
pass
|
||||
generatorcaller = isgeneratorfunction(caller)
|
||||
if generatorcaller:
|
||||
fun = FunctionMaker.create(
|
||||
func, "for res in _call_(_func_, %s%%(shortsignature)s):\n"
|
||||
" yield res" % es, evaldict, __wrapped__=func)
|
||||
else:
|
||||
fun = FunctionMaker.create(
|
||||
func, "return _call_(_func_, %s%%(shortsignature)s)" % es,
|
||||
evaldict, __wrapped__=func)
|
||||
if hasattr(func, '__qualname__'):
|
||||
fun.__qualname__ = func.__qualname__
|
||||
return fun
|
||||
|
||||
|
||||
def decoratorx(caller):
|
||||
"""
|
||||
A version of "decorator" implemented via "exec" and not via the
|
||||
Signature object. Use this if you are want to preserve the `.__code__`
|
||||
object properties (https://github.com/micheles/decorator/issues/129).
|
||||
"""
|
||||
def dec(func):
|
||||
return FunctionMaker.create(
|
||||
func,
|
||||
"return _call_(_func_, %(shortsignature)s)",
|
||||
dict(_call_=caller, _func_=func),
|
||||
__wrapped__=func, __qualname__=func.__qualname__)
|
||||
return dec
|
||||
|
||||
|
||||
def decorator(caller, _func=None, kwsyntax=False):
|
||||
"""
|
||||
decorator(caller) converts a caller function into a decorator
|
||||
"""
|
||||
def decorator(caller, _func=None):
|
||||
"""decorator(caller) converts a caller function into a decorator"""
|
||||
if _func is not None: # return a decorated function
|
||||
# this is obsolete behavior; you should use decorate instead
|
||||
return decorate(_func, caller, (), kwsyntax)
|
||||
return decorate(_func, caller)
|
||||
# else return a decorator function
|
||||
sig = inspect.signature(caller)
|
||||
dec_params = [p for p in sig.parameters.values() if p.kind is POS]
|
||||
|
||||
def dec(func=None, *args, **kw):
|
||||
na = len(args) + 1
|
||||
extras = args + tuple(kw.get(p.name, p.default)
|
||||
for p in dec_params[na:]
|
||||
if p.default is not EMPTY)
|
||||
if func is None:
|
||||
return lambda func: decorate(func, caller, extras, kwsyntax)
|
||||
defaultargs, defaults = '', ()
|
||||
if inspect.isclass(caller):
|
||||
name = caller.__name__.lower()
|
||||
doc = 'decorator(%s) converts functions/generators into ' \
|
||||
'factories of %s objects' % (caller.__name__, caller.__name__)
|
||||
elif inspect.isfunction(caller):
|
||||
if caller.__name__ == '<lambda>':
|
||||
name = '_lambda_'
|
||||
else:
|
||||
return decorate(func, caller, extras, kwsyntax)
|
||||
dec.__signature__ = sig.replace(parameters=dec_params)
|
||||
dec.__name__ = caller.__name__
|
||||
dec.__doc__ = caller.__doc__
|
||||
dec.__wrapped__ = caller
|
||||
dec.__qualname__ = caller.__qualname__
|
||||
dec.__kwdefaults__ = getattr(caller, '__kwdefaults__', None)
|
||||
dec.__dict__.update(caller.__dict__)
|
||||
name = caller.__name__
|
||||
doc = caller.__doc__
|
||||
nargs = caller.__code__.co_argcount
|
||||
ndefs = len(caller.__defaults__ or ())
|
||||
defaultargs = ', '.join(caller.__code__.co_varnames[nargs-ndefs:nargs])
|
||||
if defaultargs:
|
||||
defaultargs += ','
|
||||
defaults = caller.__defaults__
|
||||
else: # assume caller is an object with a __call__ method
|
||||
name = caller.__class__.__name__.lower()
|
||||
doc = caller.__call__.__doc__
|
||||
evaldict = dict(_call=caller, _decorate_=decorate)
|
||||
dec = FunctionMaker.create(
|
||||
'%s(func, %s)' % (name, defaultargs),
|
||||
'if func is None: return lambda func: _decorate_(func, _call, (%s))\n'
|
||||
'return _decorate_(func, _call, (%s))' % (defaultargs, defaultargs),
|
||||
evaldict, doc=doc, module=caller.__module__, __wrapped__=caller)
|
||||
if defaults:
|
||||
dec.__defaults__ = (None,) + defaults
|
||||
return dec
|
||||
|
||||
|
||||
# ####################### contextmanager ####################### #
|
||||
|
||||
try: # Python >= 3.2
|
||||
from contextlib import _GeneratorContextManager
|
||||
except ImportError: # Python >= 2.5
|
||||
from contextlib import GeneratorContextManager as _GeneratorContextManager
|
||||
|
||||
|
||||
class ContextManager(_GeneratorContextManager):
|
||||
def __init__(self, g, *a, **k):
|
||||
_GeneratorContextManager.__init__(self, g, a, k)
|
||||
|
||||
def __call__(self, func):
|
||||
def caller(f, *a, **k):
|
||||
with self.__class__(self.func, *self.args, **self.kwds):
|
||||
return f(*a, **k)
|
||||
return decorate(func, caller)
|
||||
"""Context manager decorator"""
|
||||
return FunctionMaker.create(
|
||||
func, "with _self_: return _func_(%(shortsignature)s)",
|
||||
dict(_self_=self, _func_=func), __wrapped__=func)
|
||||
|
||||
|
||||
init = getfullargspec(_GeneratorContextManager.__init__)
|
||||
n_args = len(init.args)
|
||||
if n_args == 2 and not init.varargs: # (self, genobj) Python 2.7
|
||||
def __init__(self, g, *a, **k):
|
||||
return _GeneratorContextManager.__init__(self, g(*a, **k))
|
||||
ContextManager.__init__ = __init__
|
||||
elif n_args == 2 and init.varargs: # (self, gen, *a, **k) Python 3.4
|
||||
pass
|
||||
elif n_args == 4: # (self, gen, args, kwds) Python 3.5
|
||||
def __init__(self, g, *a, **k):
|
||||
return _GeneratorContextManager.__init__(self, g, a, k)
|
||||
ContextManager.__init__ = __init__
|
||||
|
||||
_contextmanager = decorator(ContextManager)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue