diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2022-11-10 04:58:06 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-10 04:58:06 -0800 |
commit | 1de088ca95af7da6dbd1f4c715c178abd20170c4 (patch) | |
tree | c228c2c2c8069f4034c084a95577caac726ad2d8 | |
parent | gh-99320: remove tests for old-style class from `test_complex` (GH-99321) (diff) | |
download | cpython-1de088ca95af7da6dbd1f4c715c178abd20170c4.tar.gz cpython-1de088ca95af7da6dbd1f4c715c178abd20170c4.tar.bz2 cpython-1de088ca95af7da6dbd1f4c715c178abd20170c4.zip |
gh-74044: inspect.signature for wrappers around decorated bound methods (GH-736)
(cherry picked from commit dbf2faf579b4094387d65ee41f049456ca67c446)
Co-authored-by: Anton Ryzhov <anton@ryzhov.me>
-rw-r--r-- | Lib/inspect.py | 5 | ||||
-rw-r--r-- | Lib/test/test_inspect.py | 9 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2022-11-09-20-48-42.gh-issue-74044.zBj26K.rst | 1 |
3 files changed, 12 insertions, 3 deletions
diff --git a/Lib/inspect.py b/Lib/inspect.py index 5f7574c194f..d1a9daf2891 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2457,7 +2457,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 c030be77e80..a54e6eb53e6 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 00000000000..3102ef41f16 --- /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. |