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)]
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