@@ -1042,6 +1042,60 @@ async def iter_one():
10421042 asyncio .create_task (iter_one ())
10431043 return status
10441044
1045+ def test_shutdown_asyncgens_reports_base_exceptions (self ):
1046+ # gh-150866: shutdown_asyncgens silently swallowed exceptions that
1047+ # don't inherit from Exception raised during aclose() because the
1048+ # check was isinstance(result, Exception), but CancelledError inherits
1049+ # from BaseException.
1050+ self .loop ._process_events = mock .Mock ()
1051+ self .loop ._write_to_self = mock .Mock ()
1052+
1053+ class MyBaseException (BaseException ):
1054+ pass
1055+
1056+ async def agen_cancel ():
1057+ try :
1058+ yield 1
1059+ finally :
1060+ raise asyncio .CancelledError ("agen got cancelled during cleanup" )
1061+
1062+ async def agen_base ():
1063+ try :
1064+ yield 1
1065+ finally :
1066+ raise MyBaseException ("base exc during cleanup" )
1067+
1068+ async def agen_value_error ():
1069+ try :
1070+ yield 1
1071+ finally :
1072+ raise ValueError ("agen failed during cleanup" )
1073+
1074+ caught = []
1075+
1076+ def handler (loop , context ):
1077+ caught .append (context ['exception' ])
1078+
1079+ async def main ():
1080+ loop = asyncio .get_running_loop ()
1081+ loop .set_exception_handler (handler )
1082+
1083+ g1 = agen_cancel ()
1084+ g2 = agen_base ()
1085+ g3 = agen_value_error ()
1086+ await g1 .__anext__ ()
1087+ await g2 .__anext__ ()
1088+ await g3 .__anext__ ()
1089+
1090+ await loop .shutdown_asyncgens ()
1091+
1092+ self .loop .run_until_complete (main ())
1093+ self .assertEqual (len (caught ), 3 )
1094+ self .assertEqual (
1095+ {type (exc ) for exc in caught },
1096+ {asyncio .CancelledError , MyBaseException , ValueError },
1097+ )
1098+
10451099 def test_asyncgen_finalization_by_gc (self ):
10461100 # Async generators should be finalized when garbage collected.
10471101 self .loop ._process_events = mock .Mock ()
0 commit comments