Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4007086

Browse filesBrowse files
[3.11] gh-112006: Fix inspect.unwrap() for types where __wrapped__ is a data descriptor (GH-115540) (GH-115965)
(cherry picked from commit 68c79d2) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent eb13ac6 commit 4007086
Copy full SHA for 4007086

File tree

Expand file treeCollapse file tree

3 files changed

+23
-13
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+23
-13
lines changed

‎Lib/inspect.py

Copy file name to clipboardExpand all lines: Lib/inspect.py
+3-7Lines 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

Copy file name to clipboardExpand all lines: Lib/test/test_inspect/test_inspect.py
+18-6Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3273,16 +3273,20 @@ class Bar(Spam, Foo):
32733273
((('a', ..., ..., "positional_or_keyword"),),
32743274
...))
32753275

3276-
class Wrapped:
3277-
pass
3278-
Wrapped.__wrapped__ = lambda a: None
3279-
self.assertEqual(self.signature(Wrapped),
3276+
def test_signature_on_wrapper(self):
3277+
class Wrapper:
3278+
def __call__(self, b):
3279+
pass
3280+
wrapper = Wrapper()
3281+
wrapper.__wrapped__ = lambda a: None
3282+
self.assertEqual(self.signature(wrapper),
32803283
((('a', ..., ..., "positional_or_keyword"),),
32813284
...))
32823285
# wrapper loop:
3283-
Wrapped.__wrapped__ = Wrapped
3286+
wrapper = Wrapper()
3287+
wrapper.__wrapped__ = wrapper
32843288
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
3285-
self.signature(Wrapped)
3289+
self.signature(wrapper)
32863290

32873291
def test_signature_on_lambdas(self):
32883292
self.assertEqual(self.signature((lambda a=10: a)),
@@ -4433,6 +4437,14 @@ def test_recursion_limit(self):
44334437
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
44344438
inspect.unwrap(obj)
44354439

4440+
def test_wrapped_descriptor(self):
4441+
self.assertIs(inspect.unwrap(NTimesUnwrappable), NTimesUnwrappable)
4442+
self.assertIs(inspect.unwrap(staticmethod), staticmethod)
4443+
self.assertIs(inspect.unwrap(classmethod), classmethod)
4444+
self.assertIs(inspect.unwrap(staticmethod(classmethod)), classmethod)
4445+
self.assertIs(inspect.unwrap(classmethod(staticmethod)), staticmethod)
4446+
4447+
44364448
class TestMain(unittest.TestCase):
44374449
def test_only_source(self):
44384450
module = importlib.import_module('unittest')
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :func:`inspect.unwrap` for types with the ``__wrapper__`` data
2+
descriptor.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.