@@ -286,6 +286,67 @@ context manager::
286286
287287 asyncio.run(func())
288288
289+ As said above, the cleanup code for these asynchronous generators is defered.
290+ We can construct an example program to show that the finalization of the
291+ asynchronous generator is executed in an unexpected order::
292+
293+ import asyncio
294+ work_done = False
295+
296+ async def cursor():
297+ try:
298+ yield 1
299+ finally:
300+ assert work_done
301+
302+ async def rows():
303+ global work_done
304+ try:
305+ yield 2
306+ finally:
307+ await asyncio.sleep(0.1) # immitate some async work
308+ work_done = True
309+
310+
311+ async def main():
312+ async for c in cursor():
313+ async for r in rows():
314+ break
315+ break
316+
317+ asyncio.run(main())
318+
319+ For this example we get the following output::
320+
321+ unhandled exception during asyncio.run() shutdown
322+ task: <Task finished name='Task-3' coro=<<async_generator_athrow without __name__>()> exception=AssertionError()>
323+ Traceback (most recent call last):
324+ File "example.py", line 6, in cursor
325+ yield 1
326+ asyncio.exceptions.CancelledError
327+
328+ During handling of the above exception, another exception occurred:
329+
330+ Traceback (most recent call last):
331+ File "example.py", line 8, in cursor
332+ assert work_done
333+ ^^^^^^^^^
334+ AssertionError
335+
336+ The ``cursor() `` asynchronous generator was finalized before the ``rows ``
337+ generator, which we did not expect.
338+
339+ Example can be fixed by explicitly closing the
340+ ``cursor `` and ``rows `` async-generators::
341+
342+ async def main():
343+ async with contextlib.aclosing(cursor()) as cursor_gen:
344+ async for c in cursor_gen:
345+ async with contextlib.aclosing(rows()) as rows_gen:
346+ async for r in rows_gen:
347+ break
348+ break
349+
289350
290351Only create a generator when a loop is already running
291352------------------------------------------------------
@@ -349,13 +410,13 @@ Output::
349410 File "test.py", line 38, in <module>
350411 asyncio.run(amain())
351412 ~~~~~~~~~~~^^^^^^^^^
352- File "Lib\ asyncio\ runners.py", line 204, in run
413+ File "Lib/ asyncio/ runners.py", line 204, in run
353414 return runner.run(main)
354415 ~~~~~~~~~~^^^^^^
355- File "Lib\ asyncio\ runners.py", line 127, in run
416+ File "Lib/ asyncio/ runners.py", line 127, in run
356417 return self._loop.run_until_complete(task)
357418 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
358- File "Lib\ asyncio\ base_events.py", line 719, in run_until_complete
419+ File "Lib/ asyncio/ base_events.py", line 719, in run_until_complete
359420 return future.result()
360421 ~~~~~~~~~~~~~^^
361422 File "test.py", line 36, in amain
0 commit comments