https://github.com/python/cpython/commit/be833e658aaf6703b0dd0c0dadb893d72cbe4c77
commit: be833e658aaf6703b0dd0c0dadb893d72cbe4c77
branch: main
author: Shamil <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-04-22T19:31:58-07:00
summary:
gh-146553: Fix infinite loop in typing.get_type_hints() on circular __wrapped__
(#148595)
files:
A Misc/NEWS.d/next/Library/2026-04-15-11-00-39.gh-issue-146553.VGOsoP.rst
M Lib/test/test_typing.py
M Lib/typing.py
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index bfae83fdaf6bc0..6c3d67fb6b7383 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -6888,6 +6888,24 @@ def test_get_type_hints_wrapped_decoratored_func(self):
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)]
diff --git a/Lib/typing.py b/Lib/typing.py
index 3e7661dd2f877c..46e7122b6c91c5 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -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
diff --git
a/Misc/NEWS.d/next/Library/2026-04-15-11-00-39.gh-issue-146553.VGOsoP.rst
b/Misc/NEWS.d/next/Library/2026-04-15-11-00-39.gh-issue-146553.VGOsoP.rst
new file mode 100644
index 00000000000000..44216318d474a9
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-04-15-11-00-39.gh-issue-146553.VGOsoP.rst
@@ -0,0 +1,2 @@
+Fix infinite loop in :func:`typing.get_type_hints` when ``__wrapped__``
+forms a cycle. Patch by Shamil Abdulaev.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]