80 lines
2.3 KiB
Python
80 lines
2.3 KiB
Python
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
|
|
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
|
import inspect
|
|
import sys
|
|
|
|
try:
|
|
import importlib.metadata as importlib_metadata # noqa F401
|
|
except ImportError: # pragma: no cover
|
|
# bw-compat shim for py37
|
|
import importlib_metadata # noqa F401
|
|
|
|
|
|
def fix_type_error(exc_info, callable, varargs, kwargs):
|
|
"""
|
|
Given an exception, this will test if the exception was due to a
|
|
signature error, and annotate the error with better information if
|
|
so.
|
|
|
|
Usage::
|
|
|
|
try:
|
|
val = callable(*args, **kw)
|
|
except TypeError:
|
|
exc_info = fix_type_error(None, callable, args, kw)
|
|
raise exc_info[0], exc_info[1], exc_info[2]
|
|
"""
|
|
if exc_info is None:
|
|
exc_info = sys.exc_info()
|
|
if (
|
|
exc_info[0] != TypeError
|
|
or str(exc_info[1]).find('arguments') == -1
|
|
or getattr(exc_info[1], '_type_error_fixed', False)
|
|
):
|
|
return exc_info
|
|
exc_info[1]._type_error_fixed = True
|
|
argspec = inspect.formatargspec(*inspect.getargspec(callable))
|
|
args = ', '.join(map(_short_repr, varargs))
|
|
if kwargs and args:
|
|
args += ', '
|
|
if kwargs:
|
|
kwargs = sorted(kwargs.items())
|
|
args += ', '.join(['%s=...' % n for n, v in kwargs])
|
|
gotspec = '(%s)' % args
|
|
msg = f'{exc_info[1]}; got {gotspec}, wanted {argspec}'
|
|
exc_info[1].args = (msg,)
|
|
return exc_info
|
|
|
|
|
|
def _short_repr(v):
|
|
v = repr(v)
|
|
if len(v) > 12:
|
|
v = v[:8] + '...' + v[-4:]
|
|
return v
|
|
|
|
|
|
def fix_call(callable, *args, **kw):
|
|
"""
|
|
Call ``callable(*args, **kw)`` fixing any type errors that come out.
|
|
"""
|
|
try:
|
|
val = callable(*args, **kw)
|
|
except TypeError:
|
|
exc_info = fix_type_error(None, callable, args, kw)
|
|
raise exc_info[1] from None
|
|
return val
|
|
|
|
|
|
def lookup_object(spec):
|
|
"""
|
|
Looks up a module or object from a some.module:func_name specification.
|
|
To just look up a module, omit the colon and everything after it.
|
|
"""
|
|
parts, target = spec.split(':') if ':' in spec else (spec, None)
|
|
module = __import__(parts)
|
|
|
|
for part in parts.split('.')[1:] + ([target] if target else []):
|
|
module = getattr(module, part)
|
|
|
|
return module
|