@@ -646,6 +646,31 @@ def foo():
646646 get_annotations (foo , format = Format .FORWARDREF , eval_str = True )
647647 get_annotations (foo , format = Format .STRING , eval_str = True )
648648
649+ def test_eval_str_wrapped_cycle_self (self ):
650+ # gh-146556: self-referential __wrapped__ cycle must not hang.
651+ def f (x : 'int' ) -> 'str' : ...
652+ f .__wrapped__ = f
653+ # Cycle is detected and broken; globals from f itself are used.
654+ result = get_annotations (f , eval_str = True )
655+ self .assertEqual (result , {'x' : int , 'return' : str })
656+
657+ def test_eval_str_wrapped_cycle_mutual (self ):
658+ # gh-146556: mutual __wrapped__ cycle (a -> b -> a) must not hang.
659+ def a (x : 'int' ): ...
660+ def b (): ...
661+ a .__wrapped__ = b
662+ b .__wrapped__ = a
663+ result = get_annotations (a , eval_str = True )
664+ self .assertEqual (result , {'x' : int })
665+
666+ def test_eval_str_wrapped_chain_no_cycle (self ):
667+ # gh-146556: a valid (non-cyclic) __wrapped__ chain must still work.
668+ def inner (x : 'int' ): ...
669+ def outer (x : 'int' ): ...
670+ outer .__wrapped__ = inner
671+ result = get_annotations (outer , eval_str = True )
672+ self .assertEqual (result , {'x' : int })
673+
649674 def test_stock_annotations (self ):
650675 def foo (a : int , b : str ):
651676 pass
0 commit comments