/opt/imh-python/lib/python3.9/site-packages
NameSizeModeActions
amqp/-0755rm
amqp-5.3.1.dist-info/-0755rm
apache_libcloud-3.1.0.dist-info/-0755rm
appdirs-1.4.4.dist-info/-0755rm
apscheduler/-0755rm
APScheduler-3.11.0.dist-info/-0755rm
arrow/-0755rm
arrow-1.2.3.dist-info/-0755rm
astroid/-0755rm
astroid-3.3.9.dist-info/-0755rm
asttokens/-0755rm
asttokens-3.0.0.dist-info/-0755rm
attr/-0755rm
attrs/-0755rm
attrs-25.3.0.dist-info/-0755rm
autocommand/-0755rm
autocommand-2.2.2.dist-info/-0755rm
automat/-0755rm
automat-25.4.16.dist-info/-0755rm
backports/-0755rm
backports.tarfile-1.2.0.dist-info/-0755rm
bakauth/-0755rm
bakauth-1.6.2.dist-info/-0755rm
bcrypt/-0755rm
bcrypt-3.2.2.dist-info/-0755rm
billiard/-0755rm
billiard-4.2.1.dist-info/-0755rm
blessings/-0755rm
blessings-1.7.dist-info/-0755rm
boto3/-0755rm
boto3-1.16.63.dist-info/-0755rm
botocore/-0755rm
botocore-1.19.63.dist-info/-0755rm
celery/-0755rm
celery-5.4.0.dist-info/-0755rm
certifi/-0755rm
certifi-2025.4.26.dist-info/-0755rm
cffi/-0755rm
cffi-1.17.1.dist-info/-0755rm
chardet/-0755rm
chardet-3.0.4.dist-info/-0755rm
cheroot/-0755rm
cheroot-10.0.1.dist-info/-0755rm
cherrypy/-0755rm
CherryPy-18.6.1.dist-info/-0755rm
cinderclient/-0755rm
click/-0755rm
click-8.1.8.dist-info/-0755rm
click_didyoumean/-0755rm
click_didyoumean-0.3.1.dist-info/-0755rm
click_plugins/-0755rm
click_plugins-1.1.1.dist-info/-0755rm
click_repl/-0755rm
click_repl-0.3.0.dist-info/-0755rm
constantly/-0755rm
constantly-23.10.4.dist-info/-0755rm
construct/-0755rm
construct-2.10.70.dist-info/-0755rm
cpapis/-0755rm
cpapis-1.0.dist-info/-0755rm
cproc/-0755rm
cproc-1.0.dist-info/-0755rm
croniter/-0755rm
croniter-2.0.1.dist-info/-0755rm
crossplane/-0755rm
crossplane-0.5.8.dist-info/-0755rm
Crypto/-0755rm
Cryptodome/-0755rm
cryptography/-0755rm
cryptography-36.0.2.dist-info/-0755rm
cwp/-0755rm
cwp-0.1.2.dist-info/-0755rm
dateutil/-0755rm
debtcollector/-0755rm
debtcollector-3.0.0.dist-info/-0755rm
decorator-5.2.1.dist-info/-0755rm
dill/-0755rm
dill-0.4.0.dist-info/-0755rm
distro/-0755rm
distro-1.9.0.dist-info/-0755rm
dns/-0755rm
dnspython-2.7.0.dist-info/-0755rm
dogpile/-0755rm
dogpile_cache-1.4.0.dist-info/-0755rm
exceptiongroup/-0755rm
exceptiongroup-1.2.2.dist-info/-0755rm
executing/-0755rm
executing-2.2.0.dist-info/-0755rm
fabric/-0755rm
fab_classic-1.19.1.dist-info/-0755rm
flask/-0755rm
Flask-1.1.2.dist-info/-0755rm
flask_apscheduler/-0755rm
Flask_APScheduler-1.11.0.dist-info/-0755rm
flask_redis/-0755rm
flask_redis-0.4.0.dist-info/-0755rm
flask_sqlalchemy/-0755rm
Flask_SQLAlchemy-2.4.4.dist-info/-0755rm
future/-0755rm
future-1.0.0.dist-info/-0755rm
gunicorn/-0755rm
gunicorn-20.0.4.dist-info/-0755rm
hyperlink/-0755rm
hyperlink-21.0.0.dist-info/-0755rm
idna/-0755rm
idna-2.10.dist-info/-0755rm
importlib_metadata/-0755rm
importlib_metadata-4.13.0.dist-info/-0755rm
incremental/-0755rm
incremental-22.10.0.dist-info/-0755rm
influxdb/-0755rm
influxdb-5.3.2.dist-info/-0755rm
IPython/-0755rm
ipython-8.18.1.dist-info/-0755rm
iso8601/-0755rm
iso8601-2.1.0.dist-info/-0755rm
isort/-0755rm
isort-6.0.1.dist-info/-0755rm
itsdangerous/-0755rm
itsdangerous-1.1.0.dist-info/-0755rm
jaraco/-0755rm
jaraco.collections-5.1.0.dist-info/-0755rm
jaraco.context-6.0.1.dist-info/-0755rm
jaraco.functools-4.1.0.dist-info/-0755rm
jaraco.text-4.0.0.dist-info/-0755rm
jedi/-0755rm
jedi-0.19.2.dist-info/-0755rm
jinja2/-0755rm
Jinja2-2.11.3.dist-info/-0755rm
jmespath/-0755rm
jmespath-0.10.0.dist-info/-0755rm
jsonpatch-1.33.dist-info/-0755rm
jsonpointer-3.0.0.dist-info/-0755rm
keystoneauth1/-0755rm
keystoneauth1-5.10.0.dist-info/-0755rm
kombu/-0755rm
kombu-5.5.3.dist-info/-0755rm
ldap/-0755rm
libcloud/-0755rm
libfuturize/-0755rm
libpasteurize/-0755rm
markupsafe/-0755rm
MarkupSafe-1.1.1.dist-info/-0755rm
matplotlib_inline/-0755rm
matplotlib_inline-0.1.7.dist-info/-0755rm
mccabe-0.7.0.dist-info/-0755rm
mdstat/-0755rm
mdstat-1.0.4.dist-info/-0755rm
meld3/-0755rm
meld3-2.0.1.dist-info/-0755rm
more_itertools/-0755rm
more_itertools-10.7.0.dist-info/-0755rm
msgpack/-0755rm
msgpack-0.6.1.dist-info/-0755rm
mtrlib/-0755rm
mtrlib-1.2.0.dist-info/-0755rm
munch/-0755rm
munch-4.0.0.dist-info/-0755rm
nacl/-0755rm
netaddr/-0755rm
netaddr-0.8.0.dist-info/-0755rm
netifaces-0.10.9.dist-info/-0755rm
netmiko/-0755rm
netmiko-3.4.0.dist-info/-0755rm
ntc_templates/-0755rm
ntc_templates-7.8.0.dist-info/-0755rm
numpy/-0755rm
numpy-1.26.0.dist-info/-0755rm
numpy.libs/-0755rm
OpenSSL/-0755rm
openstack/-0755rm
openstacksdk-0.49.0.dist-info/-0755rm
oslo.i18n-6.5.1.dist-info/-0755rm
oslo.utils-7.1.0.dist-info/-0755rm
oslo_i18n/-0755rm
oslo_utils/-0755rm
os_client_config/-0755rm
os_client_config-2.1.0.dist-info/-0755rm
os_service_types/-0755rm
os_service_types-1.7.0.dist-info/-0755rm
packaging/-0755rm
packaging-25.0.dist-info/-0755rm
paramiko/-0755rm
paramiko-3.5.1.dist-info/-0755rm
parso/-0755rm
parso-0.8.4.dist-info/-0755rm
past/-0755rm
pbr/-0755rm
pbr-6.1.1.dist-info/-0755rm
pem/-0755rm
pem-20.1.0.dist-info/-0755rm
pexpect/-0755rm
pexpect-4.9.0.dist-info/-0755rm
picotui/-0755rm
picotui-1.2.dist-info/-0755rm
pip/-0755rm
pip-25.1.1.dist-info/-0755rm
pkg_resources/-0755rm
platformdirs/-0755rm
platformdirs-4.3.7.dist-info/-0755rm
portend-3.2.0.dist-info/-0755rm
pp_api/-0755rm
pp_api-1.3.1.dist-info/-0755rm
pr2modules/-0755rm
prettytable-0.7.2.dist-info/-0755rm
prometheus_client/-0755rm
prometheus_client-0.14.1.dist-info/-0755rm
prompt_toolkit/-0755rm
prompt_toolkit-3.0.51.dist-info/-0755rm
psutil/-0755rm
psutil-5.7.3.dist-info/-0755rm
psycopg2/-0755rm
psycopg2-2.8.6.dist-info/-0755rm
ptyprocess/-0755rm
ptyprocess-0.7.0.dist-info/-0755rm
pure_eval/-0755rm
pure_eval-0.2.3.dist-info/-0755rm
pyasn1/-0755rm
pyasn1-0.6.1.dist-info/-0755rm
pyasn1_modules/-0755rm
pyasn1_modules-0.4.2.dist-info/-0755rm
pycparser/-0755rm
pycparser-2.22.dist-info/-0755rm
pycryptodome-3.9.9.dist-info/-0755rm
pycryptodomex-3.9.9.dist-info/-0755rm
pyeapi/-0755rm
pyeapi-0.8.4.dist-info/-0755rm
pygit2/-0755rm
pygit2-1.6.1.dist-info/-0755rm
pygit2.libs/-0755rm
pygments/-0755rm
pygments-2.19.1.dist-info/-0755rm
pygraph/-0755rm
PyGraph-0.3.0.dist-info/-0755rm
pyipmi/-0755rm
pylint/-0755rm
pylint-3.3.7.dist-info/-0755rm
pymysql/-0755rm
PyMySQL-1.0.3.dist-info/-0755rm
PyNaCl-1.5.0.dist-info/-0755rm
pynetbox/-0755rm
pynetbox-6.5.0.dist-info/-0755rm
pyOpenSSL-19.1.0.dist-info/-0755rm
pyparsing/-0755rm
pyparsing-3.2.3.dist-info/-0755rm
pyroute2/-0755rm
pyroute2-0.7.12.dist-info/-0755rm
pyserial-3.5.dist-info/-0755rm
pysparklines-1.4.dist-info/-0755rm
python_cinderclient-7.1.0.dist-info/-0755rm
python_crontab-2.7.1.dist-info/-0755rm
python_dateutil-2.9.0.post0.dist-info/-0755rm
python_ipmi-0.5.7.dist-info/-0755rm
python_ldap-3.3.1.dist-info/-0755rm
python_whois-0.7.3.dist-info/-0755rm
pytz/-0755rm
pytz-2025.2.dist-info/-0755rm
pyudev/-0755rm
pyudev-0.23.2.dist-info/-0755rm
PyYAML-5.4.1.dist-info/-0755rm
pyzmq-19.0.2.dist-info/-0755rm
pyzmq.libs/-0755rm
rads/-0755rm
rads-4.1.0.dist-info/-0755rm
redis/-0755rm
redis-3.5.3.dist-info/-0755rm
requests/-0755rm
requests-2.24.0.dist-info/-0755rm
requestsexceptions/-0755rm
requestsexceptions-1.4.0.dist-info/-0755rm
restic/-0755rm
restic-1.3.5.dist-info/-0755rm
s3transfer/-0755rm
s3transfer-0.3.7.dist-info/-0755rm
scp-0.15.0.dist-info/-0755rm
serial/-0755rm
service_identity/-0755rm
service_identity-23.1.0.dist-info/-0755rm
setproctitle-1.1.10.dist-info/-0755rm
setuptools/-0755rm
setuptools-57.0.0.dist-info/-0755rm
simplejson/-0755rm
simplejson-3.20.1.dist-info/-0755rm
six-1.17.0.dist-info/-0755rm
slapdtest/-0755rm
sparkline/-0755rm
sqlalchemy/-0755rm
SQLAlchemy-1.3.24.dist-info/-0755rm
stack_data/-0755rm
stack_data-0.6.3.dist-info/-0755rm
stevedore/-0755rm
stevedore-5.4.1.dist-info/-0755rm
tabulate-0.8.10.dist-info/-0755rm
tailer/-0755rm
tailer-0.4.1.dist-info/-0755rm
tempora/-0755rm
tempora-5.8.0.dist-info/-0755rm
tenacity/-0755rm
tenacity-9.1.2.dist-info/-0755rm
test/-0755rm
testdata/-0755rm
tests/-0755rm
textfsm/-0755rm
textfsm-1.1.3.dist-info/-0755rm
toml/-0755rm
toml-0.10.2.dist-info/-0755rm
tomli/-0755rm
tomli-2.2.1.dist-info/-0755rm
tomlkit/-0755rm
tomlkit-0.13.2.dist-info/-0755rm
tornado/-0755rm
tornado-6.0.4.dist-info/-0755rm
traitlets/-0755rm
traitlets-5.14.3.dist-info/-0755rm
twisted/-0755rm
Twisted-22.4.0.dist-info/-0755rm
typing_extensions-4.13.2.dist-info/-0755rm
tzdata/-0755rm
tzdata-2025.2.dist-info/-0755rm
tzlocal/-0755rm
tzlocal-5.3.1.dist-info/-0755rm
untangle-1.1.1.dist-info/-0755rm
urllib3/-0755rm
urllib3-1.25.11.dist-info/-0755rm
uWSGI-2.0.19.1.dist-info/-0755rm
version_utils/-0755rm
version_utils-0.3.2.dist-info/-0755rm
vine/-0755rm
vine-5.1.0.dist-info/-0755rm
wcwidth/-0755rm
wcwidth-0.2.13.dist-info/-0755rm
werkzeug/-0755rm
Werkzeug-2.0.3.dist-info/-0755rm
wheel/-0755rm
wheel-0.45.1.dist-info/-0755rm
whois/-0755rm
wrapt/-0755rm
wrapt-1.17.2.dist-info/-0755rm
yaml/-0755rm
zc/-0755rm
zc.lockfile-3.0.post1.dist-info/-0755rm
zipp/-0755rm
zipp-3.21.0.dist-info/-0755rm
zmq/-0755rm
zope/-0755rm
zope.interface-7.2.dist-info/-0755rm
_distutils_hack/-0755rm
_yaml/-0755rm
__pycache__/-0755rm
appdirs.py247200644editdlrm
cronlog.py37730644editdlrm
crontab.py468620644editdlrm
crontabs.py44380644editdlrm
decorator.py170670644editdlrm
distutils-precedence.pth1520644editdlrm
jsonpatch.py297780644editdlrm
jsonpointer.py106010644editdlrm
ldapurl.py125250644editdlrm
ldif.py202780644editdlrm
LICENSE6010644editdlrm
mccabe.py106540644editdlrm
netifaces.cpython-39-x86_64-linux-gnu.so245840755editdlrm
portend.py64880644editdlrm
prettytable.py542040644editdlrm
README.md31800644editdlrm
README.txt1190644editdlrm
scp.py223930644editdlrm
setproctitle.cpython-39-x86_64-linux-gnu.so239520755editdlrm
six.py347030644editdlrm
tabulate.py738890644editdlrm
typing_extensions.py1726540644editdlrm
untangle.py55350644editdlrm
uwsgidecorators.py103920644editdlrm
zc.lockfile-3.0.post1-py3.9-nspkg.pth5190644editdlrm
zope.interface-7.2-py3.9-nspkg.pth4570644editdlrm
_cffi_backend.cpython-39-x86_64-linux-gnu.so2740960755editdlrm
_ldap.cpython-39-x86_64-linux-gnu.so956320755editdlrm
Edit: /opt/imh-python/lib/python3.9/site-packages/decorator.py (17067B)
# ######################### LICENSE ############################ # # Copyright (c) 2005-2025, Michele Simionato # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # Redistributions in bytecode form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. """ Decorator module, see https://github.com/micheles/decorator/blob/master/docs/documentation.md for the documentation. """ import re import sys import inspect import operator import itertools import functools from contextlib import _GeneratorContextManager from inspect import getfullargspec, iscoroutinefunction, isgeneratorfunction __version__ = '5.2.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 class FunctionMaker(object): """ An object with the ability to create functions with a given signature. It has attributes name, doc, module, signature, defaults, dict and methods update and make. """ # Atomic get-and-increment provided by the GIL _compile_count = itertools.count() # make pylint happy args = varargs = varkw = defaults = kwonlyargs = kwonlydefaults = () def __init__(self, func=None, name=None, signature=None, defaults=None, doc=None, module=None, funcdict=None): self.shortsignature = signature if func: # func can be a class or a callable, but not an instance method self.name = func.__name__ if self.name == '': # small hack for lambda functions self.name = '_lambda_' self.doc = func.__doc__ self.module = func.__module__ if inspect.isroutine(func) or isinstance(func, functools.partial): argspec = getfullargspec(func) self.annotations = getattr(func, '__annotations__', {}) for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs', 'kwonlydefaults'): setattr(self, a, getattr(argspec, a)) for i, arg in enumerate(self.args): setattr(self, 'arg%d' % i, arg) allargs = list(self.args) allshortargs = list(self.args) if self.varargs: allargs.append('*' + self.varargs) allshortargs.append('*' + self.varargs) elif self.kwonlyargs: allargs.append('*') # single star syntax for a in self.kwonlyargs: allargs.append('%s=None' % a) allshortargs.append('%s=%s' % (a, a)) if self.varkw: allargs.append('**' + self.varkw) allshortargs.append('**' + self.varkw) self.signature = ', '.join(allargs) self.shortsignature = ', '.join(allshortargs) self.dict = func.__dict__.copy() # func=None happens when decorating a caller if name: self.name = name if signature is not None: self.signature = signature if defaults: self.defaults = defaults if doc: self.doc = doc if module: self.module = module if funcdict: self.dict = funcdict # check existence required attributes assert hasattr(self, 'name') if not hasattr(self, 'signature'): 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 """ func.__name__ = self.name func.__doc__ = getattr(self, 'doc', None) func.__dict__ = getattr(self, 'dict', {}) func.__defaults__ = self.defaults func.__kwdefaults__ = self.kwonlydefaults or None func.__annotations__ = getattr(self, 'annotations', None) try: frame = sys._getframe(3) except AttributeError: # for IronPython and similar implementations callermodule = '?' else: callermodule = frame.f_globals.get('__name__', '?') func.__module__ = getattr(self, 'module', callermodule) 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 """ src = src_templ % vars(self) # expand name and signature evaldict = evaldict or {} mo = DEF.search(src) if mo is None: raise SyntaxError('not a valid function template\n%s' % src) name = mo.group(1) # extract the function name names = set([name] + [arg.strip(' *') for arg in self.shortsignature.split(',')]) for n in names: if n in ('_func_', '_call_'): raise NameError('%s is overridden in\n%s' % (n, src)) if not src.endswith('\n'): # add a newline for old Pythons src += '\n' # Ensure each generated function has a unique filename for profilers # (such as cProfile) that depend on the tuple of (, # , ) being unique. filename = '' % next(self._compile_count) try: code = compile(src, filename, 'single') exec(code, evaldict) except Exception: print('Error in generated code:', file=sys.stderr) print(src, file=sys.stderr) raise func = evaldict[name] if addsource: attrs['__source__'] = src self.update(func, **attrs) return func @classmethod def create(cls, obj, body, evaldict, defaults=None, doc=None, module=None, addsource=True, **attrs): """ Create a function from the strings name, signature and body. evaldict is the evaluation dictionary. If addsource is true an attribute __source__ is added to the result. The attributes attrs are added, if any. """ if isinstance(obj, str): # "name(signature)" name, rest = obj.strip().split('(', 1) signature = rest[:-1] # strip a right parens func = None else: # a function name = None signature = None func = obj self = cls(func, name, signature, defaults, doc, module) ibody = '\n'.join(' ' + line for line in body.splitlines()) caller = evaldict.get('_call_') # when called from `decorate` if caller and iscoroutinefunction(caller): body = ('async def %(name)s(%(signature)s):\n' + ibody).replace( 'return', 'return await') else: body = 'def %(name)s(%(signature)s):\n' + ibody return self.make(body, evaldict, addsource, **attrs) def fix(args, kwargs, sig): """ Fix args and kwargs to be consistent with the signature """ ba = sig.bind(*args, **kwargs) ba.apply_defaults() # needed for test_dan_schult return ba.args, ba.kwargs 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 isinstance(func, functools.partial): func = functools.update_wrapper(func, func.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 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.__name__ = func.__name__ except AttributeError: # happens with old versions of numpy.vectorize func.__name__ == 'noname' try: fun.__dict__.update(func.__dict__) except AttributeError: pass 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 """ if _func is not None: # return a decorated function # this is obsolete behavior; you should use decorate instead return decorate(_func, caller, (), kwsyntax) # 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) 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__) return dec # ####################### contextmanager ####################### # 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) _contextmanager = decorator(ContextManager) def contextmanager(func): # Enable Pylint config: contextmanager-decorators=decorator.contextmanager return _contextmanager(func) # ############################ dispatch_on ############################ # def append(a, vancestors): """ Append ``a`` to the list of the virtual ancestors, unless it is already included. """ add = True for j, va in enumerate(vancestors): if issubclass(va, a): add = False break if issubclass(a, va): vancestors[j] = a add = False if add: vancestors.append(a) # inspired from simplegeneric by P.J. Eby and functools.singledispatch def dispatch_on(*dispatch_args): """ Factory of decorators turning a function into a generic function dispatching on the given arguments. """ assert dispatch_args, 'No dispatch args passed' dispatch_str = '(%s,)' % ', '.join(dispatch_args) def check(arguments, wrong=operator.ne, msg=''): """Make sure one passes the expected number of arguments""" if wrong(len(arguments), len(dispatch_args)): raise TypeError('Expected %d arguments, got %d%s' % (len(dispatch_args), len(arguments), msg)) def gen_func_dec(func): """Decorator turning a function into a generic function""" # first check the dispatch arguments argset = set(getfullargspec(func).args) if not set(dispatch_args) <= argset: raise NameError('Unknown dispatch arguments %s' % dispatch_str) typemap = {} def vancestors(*types): """ Get a list of sets of virtual ancestors for the given types """ check(types) ras = [[] for _ in range(len(dispatch_args))] for types_ in typemap: for t, type_, ra in zip(types, types_, ras): if issubclass(t, type_) and type_ not in t.mro(): append(type_, ra) return [set(ra) for ra in ras] def ancestors(*types): """ Get a list of virtual MROs, one for each type """ check(types) lists = [] for t, vas in zip(types, vancestors(*types)): n_vas = len(vas) if n_vas > 1: raise RuntimeError( 'Ambiguous dispatch for %s: %s' % (t, vas)) elif n_vas == 1: va, = vas mro = type('t', (t, va), {}).mro()[1:] else: mro = t.mro() lists.append(mro[:-1]) # discard t and object return lists def register(*types): """ Decorator to register an implementation for the given types """ check(types) def dec(f): check(getfullargspec(f).args, operator.lt, ' in ' + f.__name__) typemap[types] = f return f return dec def dispatch_info(*types): """ An utility to introspect the dispatch algorithm """ check(types) lst = [] for ancs in itertools.product(*ancestors(*types)): lst.append(tuple(a.__name__ for a in ancs)) return lst def _dispatch(dispatch_args, *args, **kw): types = tuple(type(arg) for arg in dispatch_args) try: # fast path f = typemap[types] except KeyError: pass else: return f(*args, **kw) combinations = itertools.product(*ancestors(*types)) next(combinations) # the first one has been already tried for types_ in combinations: f = typemap.get(types_) if f is not None: return f(*args, **kw) # else call the default implementation return func(*args, **kw) return FunctionMaker.create( func, 'return _f_(%s, %%(shortsignature)s)' % dispatch_str, dict(_f_=_dispatch), register=register, default=func, typemap=typemap, vancestors=vancestors, ancestors=ancestors, dispatch_info=dispatch_info, __wrapped__=func) gen_func_dec.__name__ = 'dispatch_on' + dispatch_str return gen_func_dec