@@ -608,6 +608,68 @@ def run_gen():
608608 gc_collect ()
609609 self .assertEqual (sys .exc_info (), (None , None , None ))
610610
611+ def _check_generator_cleanup_exc_state (self , testfunc ):
612+ # Issue #12791: exception state is cleaned up as soon as a generator
613+ # is closed (reference cycles are broken).
614+ class MyException (Exception ):
615+ def __init__ (self , obj ):
616+ self .obj = obj
617+ class MyObj :
618+ pass
619+
620+ def raising_gen ():
621+ try :
622+ raise MyException (obj )
623+ except MyException :
624+ yield
625+
626+ obj = MyObj ()
627+ wr = weakref .ref (obj )
628+ g = raising_gen ()
629+ next (g )
630+ testfunc (g )
631+ g = obj = None
632+ obj = wr ()
633+ self .assertIs (obj , None )
634+
635+ def test_generator_throw_cleanup_exc_state (self ):
636+ def do_throw (g ):
637+ try :
638+ g .throw (RuntimeError ())
639+ except RuntimeError :
640+ pass
641+ self ._check_generator_cleanup_exc_state (do_throw )
642+
643+ def test_generator_close_cleanup_exc_state (self ):
644+ def do_close (g ):
645+ g .close ()
646+ self ._check_generator_cleanup_exc_state (do_close )
647+
648+ def test_generator_del_cleanup_exc_state (self ):
649+ def do_del (g ):
650+ g = None
651+ self ._check_generator_cleanup_exc_state (do_del )
652+
653+ def test_generator_next_cleanup_exc_state (self ):
654+ def do_next (g ):
655+ try :
656+ next (g )
657+ except StopIteration :
658+ pass
659+ else :
660+ self .fail ("should have raised StopIteration" )
661+ self ._check_generator_cleanup_exc_state (do_next )
662+
663+ def test_generator_send_cleanup_exc_state (self ):
664+ def do_send (g ):
665+ try :
666+ g .send (None )
667+ except StopIteration :
668+ pass
669+ else :
670+ self .fail ("should have raised StopIteration" )
671+ self ._check_generator_cleanup_exc_state (do_send )
672+
611673 def test_3114 (self ):
612674 # Bug #3114: in its destructor, MyObject retrieves a pointer to
613675 # obsolete and/or deallocated objects.
0 commit comments