@@ -609,93 +609,13 @@ async def runner():
609609 )
610610
611611 async def test_taskgroup_20b (self ):
612- # See gh-135736: a GeneratorExit raised by the "async with" body
613- # itself (e.g. propagating out of an enclosing async generator's
614- # aclose()) must propagate directly, not be wrapped in an
615- # ExceptionGroup, since callers of GeneratorExit-closing APIs
616- # only know how to handle GeneratorExit/StopAsyncIteration.
617- async def nested ():
618- try :
619- await asyncio .sleep (10 )
620- finally :
621- raise GeneratorExit
622-
623- async def runner ():
624- async with taskgroups .TaskGroup () as g :
625- await nested ()
626-
627- with self .assertRaises (GeneratorExit ):
628- await runner ()
629-
630- async def test_taskgroup_20c (self ):
631- # Same as test_taskgroup_20b, but with a sibling task that also
632- # fails. The sibling's exception can't be raised (only one
633- # exception can propagate through GeneratorExit-closing APIs),
634- # but it must be reported via the loop's exception handler
635- # instead of silently discarded.
636- async def crash_soon ():
637- await asyncio .sleep (0.1 )
638- 1 / 0
639-
640- async def nested ():
641- try :
642- await asyncio .sleep (10 )
643- finally :
644- raise GeneratorExit
645-
646- async def runner ():
647- async with taskgroups .TaskGroup () as g :
648- g .create_task (crash_soon ())
649- await nested ()
650-
651- contexts = []
652- loop = asyncio .get_running_loop ()
653- loop .set_exception_handler (lambda loop , context : contexts .append (context ))
654-
655- with self .assertRaises (GeneratorExit ):
656- await runner ()
657-
658- self .assertEqual (len (contexts ), 1 )
659- self .assertIsInstance (contexts [0 ]['exception' ], ZeroDivisionError )
660-
661- async def test_taskgroup_20d (self ):
662- # Reproduces the original report in gh-135736: closing an async
663- # generator whose body awaits inside a TaskGroup must not raise
664- # an ExceptionGroup out of aclose().
665- async def genfn ():
666- async with taskgroups .TaskGroup ():
667- yield 1
668-
669- g = genfn ()
670- await g .asend (None )
671- await g .aclose ()
672-
673- async def test_taskgroup_20e (self ):
674- # Unlike a GeneratorExit raised by the "async with" body itself
675- # (test_taskgroup_20b), a GeneratorExit raised by a *task* inside
676- # the group is not a "close this generator" signal and continues
677- # to be wrapped in an ExceptionGroup like any other exception.
678- async def crash_soon ():
679- await asyncio .sleep (0.1 )
680- raise GeneratorExit
681-
682- async def runner ():
683- async with taskgroups .TaskGroup () as g :
684- g .create_task (crash_soon ())
685- await asyncio .sleep (10 )
686-
687- with self .assertRaises (BaseExceptionGroup ) as cm :
688- await runner ()
689-
690- self .assertEqual (get_error_types (cm .exception ), {GeneratorExit })
691-
692- async def test_taskgroup_20f (self ):
693612 # Same setup as test_taskgroup_20 (a KeyboardInterrupt from the
694- # "async with" body itself, alongside a sibling task's exception),
695- # but confirms the gh-135736 fix also applies to non-GeneratorExit
696- # base errors: the sibling's exception must be reported via the
697- # loop's exception handler, the same as test_taskgroup_20c, instead
698- # of being discarded silently.
613+ # "async with" body itself, alongside a sibling task's exception):
614+ # raising self._base_error out of _aexit() discards self._errors
615+ # silently. The sibling's exception can't be raised alongside
616+ # the KeyboardInterrupt (only one exception can propagate), but
617+ # it must be reported via the loop's exception handler instead
618+ # of being discarded silently. See gh-135736.
699619 async def crash_soon ():
700620 await asyncio .sleep (0.1 )
701621 1 / 0
0 commit comments