From: Anton Ryzhov Date: Thu, 10 Nov 2022 12:32:01 +0000 (+0100) Subject: gh-74044: inspect.signature for wrappers around decorated bound methods (GH-736) X-Git-Tag: v3.12.0a2~52 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dbf2faf579b4094387d65ee41f049456ca67c446;p=thirdparty%2FPython%2Fcpython.git gh-74044: inspect.signature for wrappers around decorated bound methods (GH-736) --- diff --git a/Lib/inspect.py b/Lib/inspect.py index f6750c3b211f..d0015aa20204 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2442,7 +2442,10 @@ def _signature_from_callable(obj, *, # Was this function wrapped by a decorator? if follow_wrapper_chains: - obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__"))) + # Unwrap until we find an explicit signature or a MethodType (which will be + # handled explicitly below). + obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__") + or isinstance(f, types.MethodType))) if isinstance(obj, types.MethodType): # If the unwrapped object is a *method*, we might want to # skip its first parameter (self). diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index cfc6e411ea68..3f5c299ce681 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2960,8 +2960,6 @@ class TestSignatureObject(unittest.TestCase): self.assertEqual(str(inspect.signature(foo)), '(a)') def test_signature_on_decorated(self): - import functools - def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs) -> int: @@ -2973,6 +2971,8 @@ class TestSignatureObject(unittest.TestCase): def bar(self, a, b): pass + bar = decorator(Foo().bar) + self.assertEqual(self.signature(Foo.bar), ((('self', ..., ..., "positional_or_keyword"), ('a', ..., ..., "positional_or_keyword"), @@ -2991,6 +2991,11 @@ class TestSignatureObject(unittest.TestCase): # from "func" to "wrapper", hence no # return_annotation + self.assertEqual(self.signature(bar), + ((('a', ..., ..., "positional_or_keyword"), + ('b', ..., ..., "positional_or_keyword")), + ...)) + # Test that we handle method wrappers correctly def decorator(func): @functools.wraps(func) diff --git a/Misc/NEWS.d/next/Library/2022-11-09-20-48-42.gh-issue-74044.zBj26K.rst b/Misc/NEWS.d/next/Library/2022-11-09-20-48-42.gh-issue-74044.zBj26K.rst new file mode 100644 index 000000000000..3102ef41f162 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-11-09-20-48-42.gh-issue-74044.zBj26K.rst @@ -0,0 +1 @@ +Fixed bug where :func:`inspect.signature` reported incorrect arguments for decorated methods.