@@ -444,6 +444,11 @@ def __init__(self):
444
444
# A weak set of all asynchronous generators that are
445
445
# being iterated by the loop.
446
446
self ._asyncgens = weakref .WeakSet ()
447
+
448
+ # Strong references to asynchronous generators which are being being
449
+ # closed by the loop: see _asyncgen_finalizer_hook().
450
+ self ._close_asyncgens = set ()
451
+
447
452
# Set to True when `loop.shutdown_asyncgens` is called.
448
453
self ._asyncgens_shutdown_called = False
449
454
# Set to True when `loop.shutdown_default_executor` is called.
@@ -555,10 +560,22 @@ def _check_default_executor(self):
555
560
if self ._executor_shutdown_called :
556
561
raise RuntimeError ('Executor shutdown has been called' )
557
562
563
+ async def _asyncgen_close (self , agen ):
564
+ await agen .aclose ()
565
+ self ._close_asyncgens .discard (agen )
566
+
558
567
def _asyncgen_finalizer_hook (self , agen ):
568
+ if self .is_closed ():
569
+ self ._asyncgens .discard (agen )
570
+ return
571
+
572
+ # gh-117536: Store a strong reference to the asynchronous generator
573
+ # to make sure that shutdown_asyncgens() can close it even if
574
+ # asyncio.run() cancels all tasks.
575
+ self ._close_asyncgens .add (agen )
559
576
self ._asyncgens .discard (agen )
560
- if not self . is_closed ():
561
- self .call_soon_threadsafe (self .create_task , agen . aclose ( ))
577
+
578
+ self .call_soon_threadsafe (self .create_task , self . _asyncgen_close ( agen ))
562
579
563
580
def _asyncgen_firstiter_hook (self , agen ):
564
581
if self ._asyncgens_shutdown_called :
@@ -573,12 +590,12 @@ async def shutdown_asyncgens(self):
573
590
"""Shutdown all active asynchronous generators."""
574
591
self ._asyncgens_shutdown_called = True
575
592
576
- if not len (self ._asyncgens ):
593
+ closing_agens = list (set (self ._asyncgens ) | self ._close_asyncgens )
594
+ if not closing_agens :
577
595
# If Python version is <3.6 or we don't have any asynchronous
578
596
# generators alive.
579
597
return
580
598
581
- closing_agens = list (self ._asyncgens )
582
599
self ._asyncgens .clear ()
583
600
584
601
results = await tasks .gather (
0 commit comments