def _get_function_source(func):
if _PY34:
func = inspect.unwrap(func)
elif hasattr(func, '__wrapped__'):
func = func.__wrapped__
if inspect.isfunction(func):
code = func.__code__
return (code.co_filename, code.co_firstlineno)
if isinstance(func, functools.partial):
return _get_function_source(func.func)
if _PY34 and isinstance(func, functools.partialmethod):
return _get_function_source(func.func)
return None
python类unwrap()的实例源码
def unwrap(func, stop=None):
# NOTE: implementation is taken from CPython/Lib/inspect.py, Python 3.6
if stop is None:
def _is_wrapper(f):
return hasattr(f, '__wrapped__')
else:
def _is_wrapper(f):
return hasattr(f, '__wrapped__') and not stop(f)
f = func # remember the original func for error reporting
memo = {id(f)} # Memoise by id to tolerate non-hashable objects
while _is_wrapper(func):
func = func.__wrapped__
id_func = id(func)
if id_func in memo:
raise ValueError('wrapper loop when unwrapping {!r}'.format(f))
memo.add(id_func)
return func
def _collect_grammar_rules(func):
grammar = []
while func:
prodname = func.__name__
unwrapped = inspect.unwrap(func)
filename = unwrapped.__code__.co_filename
lineno = unwrapped.__code__.co_firstlineno
for rule, lineno in zip(func.rules, range(lineno+len(func.rules)-1, 0, -1)):
syms = rule.split()
if syms[1:2] == [':'] or syms[1:2] == ['::=']:
grammar.append((func, filename, lineno, syms[0], syms[2:]))
else:
grammar.append((func, filename, lineno, prodname, syms))
func = getattr(func, 'next_func', None)
return grammar
def _unwrap_func(cls, decorated_func):
'''This unwraps a decorated func, returning the inner wrapped func.
This may become unnecessary with Python 3.4's inspect.unwrap().
'''
if click is not None:
# Workaround for click.command() decorator not setting
# __wrapped__
if isinstance(decorated_func, click.Command):
return cls._unwrap_func(decorated_func.callback)
if hasattr(decorated_func, '__wrapped__'):
# Recursion: unwrap more if needed
return cls._unwrap_func(decorated_func.__wrapped__)
else:
# decorated_func isn't actually decorated, no more
# unwrapping to do
return decorated_func
def get_func_in_module(module: str, qualname: str) -> Callable:
"""Return the function specified by qualname in module.
Raises:
NameLookupError if we can't find the named function
InvalidTypeError if we the name isn't a function
"""
func = get_name_in_module(module, qualname)
# TODO: Incorrect typeshed stub, stop arg should be optional
# https://github.com/python/typeshed/blob/master/stdlib/3/inspect.pyi#L213
func = inspect.unwrap(func) # type: ignore
if isinstance(func, types.MethodType):
func = func.__func__
elif isinstance(func, property):
if func.fget is not None:
if (func.fset is None) and (func.fdel is None):
func = func.fget
else:
raise InvalidTypeError(
f"Property {module}.{qualname} has setter or deleter.")
else:
raise InvalidTypeError(
f"Property {module}.{qualname} is missing getter")
elif not isinstance(func, (types.FunctionType, types.BuiltinFunctionType)):
raise InvalidTypeError(
f"{module}.{qualname} is of type '{type(func)}', not function.")
return func
def _get_function_source(func):
if compat.PY34:
func = inspect.unwrap(func)
elif hasattr(func, '__wrapped__'):
func = func.__wrapped__
if inspect.isfunction(func):
code = func.__code__
return (code.co_filename, code.co_firstlineno)
if isinstance(func, functools.partial):
return _get_function_source(func.func)
if compat.PY34 and isinstance(func, functools.partialmethod):
return _get_function_source(func.func)
return None
def _get_function_source(func):
if compat.PY34:
func = inspect.unwrap(func)
elif hasattr(func, '__wrapped__'):
func = func.__wrapped__
if inspect.isfunction(func):
code = func.__code__
return (code.co_filename, code.co_firstlineno)
if isinstance(func, functools.partial):
return _get_function_source(func.func)
if compat.PY34 and isinstance(func, functools.partialmethod):
return _get_function_source(func.func)
return None
def test_unwrap_one(self):
def func(a, b):
return a + b
wrapper = functools.lru_cache(maxsize=20)(func)
self.assertIs(inspect.unwrap(wrapper), func)
def test_unwrap_several(self):
def func(a, b):
return a + b
wrapper = func
for __ in range(10):
@functools.wraps(wrapper)
def wrapper():
pass
self.assertIsNot(wrapper.__wrapped__, func)
self.assertIs(inspect.unwrap(wrapper), func)
def test_stop(self):
def func1(a, b):
return a + b
@functools.wraps(func1)
def func2():
pass
@functools.wraps(func2)
def wrapper():
pass
func2.stop_here = 1
unwrapped = inspect.unwrap(wrapper,
stop=(lambda f: hasattr(f, "stop_here")))
self.assertIs(unwrapped, func2)
def test_cycle(self):
def func1(): pass
func1.__wrapped__ = func1
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func1)
def func2(): pass
func2.__wrapped__ = func1
func1.__wrapped__ = func2
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func1)
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func2)
def _get_function_source(func):
if _PY34:
func = inspect.unwrap(func)
elif hasattr(func, '__wrapped__'):
func = func.__wrapped__
if inspect.isfunction(func):
code = func.__code__
return (code.co_filename, code.co_firstlineno)
if isinstance(func, functools.partial):
return _get_function_source(func.func)
if _PY34 and isinstance(func, functools.partialmethod):
return _get_function_source(func.func)
return None
def test_unwrap_one(self):
def func(a, b):
return a + b
wrapper = functools.lru_cache(maxsize=20)(func)
self.assertIs(inspect.unwrap(wrapper), func)
def test_unwrap_several(self):
def func(a, b):
return a + b
wrapper = func
for __ in range(10):
@functools.wraps(wrapper)
def wrapper():
pass
self.assertIsNot(wrapper.__wrapped__, func)
self.assertIs(inspect.unwrap(wrapper), func)
def test_stop(self):
def func1(a, b):
return a + b
@functools.wraps(func1)
def func2():
pass
@functools.wraps(func2)
def wrapper():
pass
func2.stop_here = 1
unwrapped = inspect.unwrap(wrapper,
stop=(lambda f: hasattr(f, "stop_here")))
self.assertIs(unwrapped, func2)
def test_cycle(self):
def func1(): pass
func1.__wrapped__ = func1
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func1)
def func2(): pass
func2.__wrapped__ = func1
func1.__wrapped__ = func2
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func1)
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func2)