gh-146553: Fix infinite loop in typing.get_type_hints() on circular __wrapped__ (#148595)

This commit is contained in:
Shamil
2026-04-23 05:31:58 +03:00
committed by GitHub
parent 79321fdce3
commit be833e658a
3 changed files with 24 additions and 0 deletions
+18
View File
@@ -6888,6 +6888,24 @@ class GetTypeHintsTests(BaseTestCase):
self.assertEqual(gth(ForRefExample.func), expects)
self.assertEqual(gth(ForRefExample.nested), expects)
def test_get_type_hints_wrapped_cycle_self(self):
# gh-146553: __wrapped__ self-reference must raise ValueError,
# not loop forever.
def f(x: int) -> str: ...
f.__wrapped__ = f
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
get_type_hints(f)
def test_get_type_hints_wrapped_cycle_mutual(self):
# gh-146553: mutual __wrapped__ cycle (a -> b -> a) must raise
# ValueError, not loop forever.
def a(): ...
def b(): ...
a.__wrapped__ = b
b.__wrapped__ = a
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
get_type_hints(a)
def test_get_type_hints_annotated(self):
def foobar(x: List['X']): ...
X = Annotated[int, (1, 10)]
+4
View File
@@ -2486,8 +2486,12 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
else:
nsobj = obj
# Find globalns for the unwrapped object.
seen = {id(nsobj)}
while hasattr(nsobj, '__wrapped__'):
nsobj = nsobj.__wrapped__
if id(nsobj) in seen:
raise ValueError(f'wrapper loop when unwrapping {obj!r}')
seen.add(id(nsobj))
globalns = getattr(nsobj, '__globals__', {})
if localns is None:
localns = globalns
@@ -0,0 +1,2 @@
Fix infinite loop in :func:`typing.get_type_hints` when ``__wrapped__``
forms a cycle. Patch by Shamil Abdulaev.