Skip to content

Commit dbf2faf

Browse files
authored
gh-74044: inspect.signature for wrappers around decorated bound methods (GH-736)
1 parent 9d69284 commit dbf2faf

File tree

3 files changed

+12
-3
lines changed

3 files changed

+12
-3
lines changed

Lib/inspect.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2442,7 +2442,10 @@ def _signature_from_callable(obj, *,
24422442

24432443
# Was this function wrapped by a decorator?
24442444
if follow_wrapper_chains:
2445-
obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))
2445+
# Unwrap until we find an explicit signature or a MethodType (which will be
2446+
# handled explicitly below).
2447+
obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")
2448+
or isinstance(f, types.MethodType)))
24462449
if isinstance(obj, types.MethodType):
24472450
# If the unwrapped object is a *method*, we might want to
24482451
# skip its first parameter (self).

Lib/test/test_inspect.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2960,8 +2960,6 @@ def foo(a): pass
29602960
self.assertEqual(str(inspect.signature(foo)), '(a)')
29612961

29622962
def test_signature_on_decorated(self):
2963-
import functools
2964-
29652963
def decorator(func):
29662964
@functools.wraps(func)
29672965
def wrapper(*args, **kwargs) -> int:
@@ -2973,6 +2971,8 @@ class Foo:
29732971
def bar(self, a, b):
29742972
pass
29752973

2974+
bar = decorator(Foo().bar)
2975+
29762976
self.assertEqual(self.signature(Foo.bar),
29772977
((('self', ..., ..., "positional_or_keyword"),
29782978
('a', ..., ..., "positional_or_keyword"),
@@ -2991,6 +2991,11 @@ def bar(self, a, b):
29912991
# from "func" to "wrapper", hence no
29922992
# return_annotation
29932993

2994+
self.assertEqual(self.signature(bar),
2995+
((('a', ..., ..., "positional_or_keyword"),
2996+
('b', ..., ..., "positional_or_keyword")),
2997+
...))
2998+
29942999
# Test that we handle method wrappers correctly
29953000
def decorator(func):
29963001
@functools.wraps(func)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed bug where :func:`inspect.signature` reported incorrect arguments for decorated methods.

0 commit comments

Comments
 (0)