diff -r f3dbeca1e30d Doc/library/inspect.rst --- a/Doc/library/inspect.rst Tue May 19 21:06:04 2015 +0200 +++ b/Doc/library/inspect.rst Tue May 19 17:17:09 2015 -0400 @@ -431,7 +431,7 @@ return annotation. To retrieve a Signature object, use the :func:`signature` function. -.. function:: signature(callable) +.. function:: signature(callable, \*, follow_wrapped=True) Return a :class:`Signature` object for the given ``callable``:: @@ -456,6 +456,11 @@ Raises :exc:`ValueError` if no signature can be provided, and :exc:`TypeError` if that type of object is not supported. + .. versionadded:: 3.5 + ``follow_wrapped`` parameter. Pass ``False`` to get a signature of + ``callable`` specifically (``callable.__wrapped__`` will not be used to + unwrap decorated callables.) + .. note:: Some callables may not be introspectable in certain implementations of @@ -528,12 +533,13 @@ >>> str(new_sig) "(a, b) -> 'new return anno'" - .. classmethod:: Signature.from_callable(obj) + .. classmethod:: Signature.from_callable(obj, \*, follow_wrapped=True) Return a :class:`Signature` (or its subclass) object for a given callable - ``obj``. This method simplifies subclassing of :class:`Signature`: + ``obj``. Pass ``follow_wrapped=False`` to get a signature of ``obj`` + without unwrapping its ``__wrapped__`` chain. - :: + This method simplifies subclassing of :class:`Signature`:: class MySignature(Signature): pass diff -r f3dbeca1e30d Lib/inspect.py --- a/Lib/inspect.py Tue May 19 21:06:04 2015 +0200 +++ b/Lib/inspect.py Tue May 19 17:17:09 2015 -0400 @@ -2664,9 +2664,10 @@ return _signature_from_builtin(cls, func) @classmethod - def from_callable(cls, obj): + def from_callable(cls, obj, *, follow_wrapped=True): """Constructs Signature for the given callable object.""" - return _signature_from_callable(obj, sigcls=cls) + return _signature_from_callable(obj, sigcls=cls, + follow_wrapper_chains=follow_wrapped) @property def parameters(self): @@ -2915,9 +2916,9 @@ return rendered -def signature(obj): +def signature(obj, *, follow_wrapped=True): """Get a signature object for the passed callable.""" - return Signature.from_callable(obj) + return Signature.from_callable(obj, follow_wrapped=follow_wrapped) def _main(): diff -r f3dbeca1e30d Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py Tue May 19 21:06:04 2015 +0200 +++ b/Lib/test/test_inspect.py Tue May 19 17:17:09 2015 -0400 @@ -1735,8 +1735,8 @@ class TestSignatureObject(unittest.TestCase): @staticmethod - def signature(func): - sig = inspect.signature(func) + def signature(func, **kw): + sig = inspect.signature(func, **kw) return (tuple((param.name, (... if param.default is param.empty else param.default), (... if param.annotation is param.empty @@ -1956,6 +1956,11 @@ self.assertEqual(inspect.signature(func), inspect.signature(decorated_func)) + def wrapper_like(*args, **kwargs) -> int: pass + self.assertEqual(inspect.signature(decorated_func, + follow_wrapped=False), + inspect.signature(wrapper_like)) + @cpython_only def test_signature_on_builtins_no_signature(self): import _testcapi @@ -2384,6 +2389,13 @@ ('b', ..., ..., "positional_or_keyword")), ...)) + self.assertEqual(self.signature(Foo.bar, follow_wrapped=False), + ((('args', ..., ..., "var_positional"), + ('kwargs', ..., ..., "var_keyword")), + ...)) # functools.wraps will copy __annotations__ + # from "func" to "wrapper", hence no + # return_annotation + # Test that we handle method wrappers correctly def decorator(func): @functools.wraps(func)