Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f540bc9

Browse files
[3.13] gh-146553: Fix infinite loop in typing.get_type_hints() on circular __wrapped__ (GH-148595) (#148896)
(cherry picked from commit be833e6) Co-authored-by: Shamil <[email protected]>
1 parent a52c8cb commit f540bc9

3 files changed

Lines changed: 24 additions & 0 deletions

File tree

Lib/test/test_typing.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6979,6 +6979,24 @@ def test_get_type_hints_wrapped_decoratored_func(self):
69796979
self.assertEqual(gth(ForRefExample.func), expects)
69806980
self.assertEqual(gth(ForRefExample.nested), expects)
69816981

6982+
def test_get_type_hints_wrapped_cycle_self(self):
6983+
# gh-146553: __wrapped__ self-reference must raise ValueError,
6984+
# not loop forever.
6985+
def f(x: int) -> str: ...
6986+
f.__wrapped__ = f
6987+
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
6988+
get_type_hints(f)
6989+
6990+
def test_get_type_hints_wrapped_cycle_mutual(self):
6991+
# gh-146553: mutual __wrapped__ cycle (a -> b -> a) must raise
6992+
# ValueError, not loop forever.
6993+
def a(): ...
6994+
def b(): ...
6995+
a.__wrapped__ = b
6996+
b.__wrapped__ = a
6997+
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
6998+
get_type_hints(a)
6999+
69827000
def test_get_type_hints_annotated(self):
69837001
def foobar(x: List['X']): ...
69847002
X = Annotated[int, (1, 10)]

Lib/typing.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2483,8 +2483,12 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
24832483
else:
24842484
nsobj = obj
24852485
# Find globalns for the unwrapped object.
2486+
seen = {id(nsobj)}
24862487
while hasattr(nsobj, '__wrapped__'):
24872488
nsobj = nsobj.__wrapped__
2489+
if id(nsobj) in seen:
2490+
raise ValueError(f'wrapper loop when unwrapping {obj!r}')
2491+
seen.add(id(nsobj))
24882492
globalns = getattr(nsobj, '__globals__', {})
24892493
if localns is None:
24902494
localns = globalns
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix infinite loop in :func:`typing.get_type_hints` when ``__wrapped__``
2+
forms a cycle. Patch by Shamil Abdulaev.

0 commit comments

Comments
 (0)