@@ -630,6 +630,89 @@ def genfn():
630630 self .assertIsNone (f_wr ())
631631
632632
633+ # See https://github.com/python/cpython/issues/125723
634+ class GeneratorDeallocTest (unittest .TestCase ):
635+ def test_frame_outlives_generator (self ):
636+ def g1 ():
637+ a = 42
638+ yield sys ._getframe ()
639+
640+ def g2 ():
641+ a = 42
642+ yield
643+
644+ def g3 (obj ):
645+ a = 42
646+ obj .frame = sys ._getframe ()
647+ yield
648+
649+ class ObjectWithFrame ():
650+ def __init__ (self ):
651+ self .frame = None
652+
653+ def get_frame (index ):
654+ if index == 1 :
655+ return next (g1 ())
656+ elif index == 2 :
657+ gen = g2 ()
658+ next (gen )
659+ return gen .gi_frame
660+ elif index == 3 :
661+ obj = ObjectWithFrame ()
662+ next (g3 (obj ))
663+ return obj .frame
664+ else :
665+ return None
666+
667+ for index in (1 , 2 , 3 ):
668+ with self .subTest (index = index ):
669+ frame = get_frame (index )
670+ frame_locals = frame .f_locals
671+ self .assertIn ('a' , frame_locals )
672+ self .assertEqual (frame_locals ['a' ], 42 )
673+
674+ def test_frame_locals_outlive_generator (self ):
675+ frame_locals1 = None
676+
677+ def g1 ():
678+ nonlocal frame_locals1
679+ frame_locals1 = sys ._getframe ().f_locals
680+ a = 42
681+ yield
682+
683+ def g2 ():
684+ a = 42
685+ yield sys ._getframe ().f_locals
686+
687+ def get_frame_locals (index ):
688+ if index == 1 :
689+ nonlocal frame_locals1
690+ next (g1 ())
691+ return frame_locals1
692+ if index == 2 :
693+ return next (g2 ())
694+ else :
695+ return None
696+
697+ for index in (1 , 2 ):
698+ with self .subTest (index = index ):
699+ frame_locals = get_frame_locals (index )
700+ self .assertIn ('a' , frame_locals )
701+ self .assertEqual (frame_locals ['a' ], 42 )
702+
703+ def test_frame_locals_outlive_generator_with_exec (self ):
704+ def g ():
705+ a = 42
706+ yield locals (), sys ._getframe ().f_locals
707+
708+ locals_ = {'g' : g }
709+ for i in range (10 ):
710+ exec ("snapshot, live_locals = next(g())" , locals = locals_ )
711+ for l in (locals_ ['snapshot' ], locals_ ['live_locals' ]):
712+ self .assertIn ('a' , l )
713+ self .assertEqual (l ['a' ], 42 )
714+
715+
633716class GeneratorThrowTest (unittest .TestCase ):
634717
635718 def test_exception_context_with_yield (self ):
0 commit comments