8000 gh-112006: Fix inspect.unwrap() for types where __wrapped__ is a data… · miss-islington/cpython@6f4602f · GitHub
[go: up one dir, main page]

Skip to content

Commit 6f4602f

Browse files
serhiy-storchakamiss-islington
authored andcommitted
pythongh-112006: Fix inspect.unwrap() for types where __wrapped__ is a data descriptor (pythonGH-115540)
This also fixes inspect.Signature.from_callable() for builtins classmethod() and staticmethod(). (cherry picked from commit 68c79d2) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent a30a1e7 commit 6f4602f

File tree

3 files changed

+32
-13
lines changed

3 files changed

+32
-13
lines changed

Lib/inspect.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -748,18 +748,14 @@ def unwrap(func, *, stop=None):
748748
:exc:`ValueError` is raised if a cycle is encountered.
749749
750750
"""
751-
if stop is None:
752-
def _is_wrapper(f):
753-
return hasattr(f, '__wrapped__')
754-
else:
755-
def _is_wrapper(f):
756-
return hasattr(f, '__wrapped__') and not stop(f)
757751
f = func # remember the original func for error reporting
758752
# Memoise by id to tolerate non-hashable objects, but store objects to
759753
# ensure they aren't destroyed, which would allow their IDs to be reused.
760754
memo = {id(f): f}
761755
recursion_limit = sys.getrecursionlimit()
762-
while _is_wrapper(func):
756+
while not isinstance(func, type) and hasattr(func, '__wrapped__'):
757+
if stop is not None and stop(func):
758+
break
763759
func = func.__wrapped__
764760
id_func = id(func)
765761
if (id_func in memo) or (len(memo) >= recursion_limit):

Lib/test/test_inspect/test_inspect.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,6 +2732,10 @@ def m1d(*args, **kwargs):
27322732
int))
27332733

27342734
def test_signature_on_classmethod(self):
2735+
self.assertEqual(self.signature(classmethod),
2736+
((('function', ..., ..., "positional_only"),),
2737+
...))
2738+
27352739
class Test:
27362740
@classmethod
27372741
def foo(cls, arg1, *, arg2=1):
@@ -2750,6 +2754,10 @@ def foo(cls, arg1, *, arg2=1):
27502754
...))
27512755

27522756
def test_signature_on_staticmethod(self):
2757+
self.assertEqual(self.signature(staticmethod),
2758+
((('function', ..., ..., "positional_only"),),
2759+
...))
2760+
27532761
class Test:
27542762
@staticmethod
27552763
def foo(cls, *, arg):
@@ -3273,16 +3281,20 @@ class Bar(Spam, Foo):
32733281
((('a', ..., ..., "positional_or_keyword"),),
32743282
...))
32753283

3276-
class Wrapped:
3277-
pass
3278-
Wrapped.__wrapped__ = lambda a: None
3279-
self.assertEqual(self.signature(Wrapped),
3284+
def test_signature_on_wrapper(self):
3285+
class Wrapper:
3286+
def __call__(self, b):
3287+
pass
3288+
wrapper = Wrapper()
3289+
wrapper.__wrapped__ = lambda a: None
3290+
self.assertEqual(self.signature(wrapper),
32803291
((('a', ..., ..., "positional_or_keyword"),),
32813292
...))
32823293
# wrapper loop:
3283-
Wrapped.__wrapped__ = Wrapped
3294+
wrapper = Wrapper()
3295+
wrapper.__wrapped__ = wrapper
32843296
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
3285-
self.signature(Wrapped)
3297+
self.signature(wrapper)
32863298

32873299
def test_signature_on_lambdas(self):
32883300
self.assertEqual(self.signature((lambda a=10: a)),
@@ -4433,6 +4445,14 @@ def test_recursion_limit(self):
44334445
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
44344446
inspect.unwrap(obj)
44354447

4448+
def test_wrapped_descriptor(self):
4449+
self.assertIs(inspect.unwrap(NTimesUnwrappable), NTimesUnwrappable)
4450+
self.assertIs(inspect.unwrap(staticmethod), staticmethod)
4451+
self.assertIs(inspect.unwrap(classmethod), classmethod)
4452+
self.assertIs(inspect.unwrap(staticmethod(classmethod)), classmethod)
4453+
self.assertIs(inspect.unwrap(classmethod(staticmethod)), staticmethod)
4454+
4455+
44364456
class TestMain(unittest.TestCase):
44374457
def test_only_source(self):
44384458
module = importlib.import_module('unittest')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :func:`inspect.unwrap` for types with the ``__wrapper__`` data
2+
descriptor. Fix :meth:`inspect.Signature.from_callable` for builtins
3+
:func:`classmethod` and :func:`staticmethod`.

0 commit comments

Comments
 (0)
0