From e1b645c56f446b65964c94d7fe87e217f1816359 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Thu, 5 Dec 2024 15:51:17 +0000 Subject: [PATCH 1/8] gh-127174: add some advice for asyncio.get_event_loop replacements --- Doc/whatsnew/3.14.rst | 86 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index e83c509a025ab5..d75e8d28066419 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -771,6 +771,92 @@ asyncio * Removed implicit creation of event loop by :func:`asyncio.get_event_loop`. It now raises a :exc:`RuntimeError` if there is no current event loop. (Contributed by Kumar Aditya in :gh:`126353`.) + There's a few patterns that use :func:`asyncio.get_event_loop`, most + of them can be replaced with :func:`asyncio.run`. + + If you're running an async function, simply use :func:`asyncio.run`, + before:: + + async def amain(): + ... + + loop = asyncio.get_event_loop() + try: + loop.run_until_complete(amain()) + finally: + loop.close() + + after:: + + async def amain(): + ... + + asyncio.run(amain()) + + If you need to start something, eg, a server listening on a socket + and then run forever, use :func:`asyncio.run` and an + :class:`asyncio.Event`, before:: + + def start_server(loop): + ... + + loop = asyncio.get_event_loop() + try: + start_server(loop) + loop.run_forever() + finally: + loop.close() + + after:: + + def start_server(loop): + ... + + async def amain(): + start_server(asyncio.get_running_loop()) + await asyncio.Event().wait() + + asyncio.run(amain()) + + If you need to run something in an event loop, then run some blocking + code around it, use :class:`asyncio.Runner`, before:: + + async def operation_one(): + ... + + def blocking_code(): + ... + + async def operation_two(): + ... + + loop = asyncio.get_event_loop() + try: + loop.run_until_complete(operation_one()) + blocking_code() + loop.run_until_complete(operation_two()) + finally: + loop.close() + + after:: + + async def operation_one(): + ... + + def blocking_code(): + ... + + async def operation_two(): + ... + + with asyncio.Runner() as runner: + runner.run(operation_one()) + blocking_code() + runner.run(operation_two()) + + If you need an 'ambient' event loop, shared between multiple otherwise + unrelated modules, this is the sort of use-case that's no longer supported + in asyncio. collections.abc From 9bb412d56d47f34c98b7be047a36d58c41b72359 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Thu, 5 Dec 2024 16:31:28 +0000 Subject: [PATCH 2/8] Apply suggestions from code review Co-authored-by: Kumar Aditya --- Doc/whatsnew/3.14.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index d75e8d28066419..df12f59a89c091 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -777,7 +777,7 @@ asyncio If you're running an async function, simply use :func:`asyncio.run`, before:: - async def amain(): + async def main(): ... loop = asyncio.get_event_loop() @@ -788,12 +788,12 @@ asyncio after:: - async def amain(): + async def main(): ... - asyncio.run(amain()) + asyncio.run(main()) - If you need to start something, eg, a server listening on a socket + If you need to start something, e.g. a server listening on a socket and then run forever, use :func:`asyncio.run` and an :class:`asyncio.Event`, before:: From b98954dda31294d6253c0545b71791d477ef58e3 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Fri, 6 Dec 2024 06:42:46 +0000 Subject: [PATCH 3/8] remove note about ambient event loops --- Doc/whatsnew/3.14.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index df12f59a89c091..b267420be864fa 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -854,9 +854,6 @@ asyncio blocking_code() runner.run(operation_two()) - If you need an 'ambient' event loop, shared between multiple otherwise - unrelated modules, this is the sort of use-case that's no longer supported - in asyncio. collections.abc From 588b20fece62c68252e1aaed442ce7abeebb5e8b Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sat, 7 Dec 2024 16:47:01 +0530 Subject: [PATCH 4/8] Update Doc/whatsnew/3.14.rst --- Doc/whatsnew/3.14.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index b267420be864fa..c84b2de4445d19 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -774,7 +774,8 @@ asyncio There's a few patterns that use :func:`asyncio.get_event_loop`, most of them can be replaced with :func:`asyncio.run`. - If you're running an async function, simply use :func:`asyncio.run`, + If you're running an async function, simply use :func:`asyncio.run`. + before:: async def main(): From bdf970ce89725621bc8da4ac0c7344c0db565a3e Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sat, 7 Dec 2024 16:47:32 +0530 Subject: [PATCH 5/8] Update Doc/whatsnew/3.14.rst --- Doc/whatsnew/3.14.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index c84b2de4445d19..ab30b3d6b59938 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -796,7 +796,9 @@ asyncio If you need to start something, e.g. a server listening on a socket and then run forever, use :func:`asyncio.run` and an - :class:`asyncio.Event`, before:: + :class:`asyncio.Event`. + + before:: def start_server(loop): ... From 34058744c596c19e7d0034e547ab84accd04dfe2 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sat, 7 Dec 2024 16:56:37 +0530 Subject: [PATCH 6/8] put before on nl --- Doc/whatsnew/3.14.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index ab30b3d6b59938..0affd343bfddb5 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -775,7 +775,7 @@ asyncio of them can be replaced with :func:`asyncio.run`. If you're running an async function, simply use :func:`asyncio.run`. - + before:: async def main(): @@ -797,7 +797,7 @@ asyncio If you need to start something, e.g. a server listening on a socket and then run forever, use :func:`asyncio.run` and an :class:`asyncio.Event`. - + before:: def start_server(loop): @@ -815,14 +815,16 @@ asyncio def start_server(loop): ... - async def amain(): + async def main(): start_server(asyncio.get_running_loop()) await asyncio.Event().wait() - asyncio.run(amain()) + asyncio.run(main()) If you need to run something in an event loop, then run some blocking - code around it, use :class:`asyncio.Runner`, before:: + code around it, use :class:`asyncio.Runner`. + + before:: async def operation_one(): ... From d0c6e950c1a3714f1e151929e94cb68d0f065f5b Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Wed, 18 Dec 2024 12:46:26 +0530 Subject: [PATCH 7/8] improve docs --- Doc/whatsnew/3.14.rst | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 0affd343bfddb5..80dc17a850f9e1 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -776,18 +776,19 @@ asyncio If you're running an async function, simply use :func:`asyncio.run`. - before:: + Before:: async def main(): ... + loop = asyncio.get_event_loop() try: - loop.run_until_complete(amain()) + loop.run_until_complete(main()) finally: - loop.close() + loop.close() - after:: + After:: async def main(): ... @@ -798,7 +799,7 @@ asyncio and then run forever, use :func:`asyncio.run` and an :class:`asyncio.Event`. - before:: + Before:: def start_server(loop): ... @@ -810,7 +811,7 @@ asyncio finally: loop.close() - after:: + After:: def start_server(loop): ... @@ -824,7 +825,7 @@ asyncio If you need to run something in an event loop, then run some blocking code around it, use :class:`asyncio.Runner`. - before:: + Before:: async def operation_one(): ... @@ -837,13 +838,13 @@ asyncio loop = asyncio.get_event_loop() try: - loop.run_until_complete(operation_one()) - blocking_code() - loop.run_until_complete(operation_two()) + loop.run_until_complete(operation_one()) + blocking_code() + loop.run_until_complete(operation_two()) finally: - loop.close() + loop.close() - after:: + After:: async def operation_one(): ... @@ -855,9 +856,9 @@ asyncio ... with asyncio.Runner() as runner: - runner.run(operation_one()) - blocking_code() - runner.run(operation_two()) + runner.run(operation_one()) + blocking_code() + runner.run(operation_two()) From d30832e01fc833d3f1f5b2492a523a36485e9481 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Wed, 18 Dec 2024 12:50:36 +0530 Subject: [PATCH 8/8] format --- Doc/whatsnew/3.14.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 80dc17a850f9e1..65ffe67c4c7204 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -771,6 +771,7 @@ asyncio * Removed implicit creation of event loop by :func:`asyncio.get_event_loop`. It now raises a :exc:`RuntimeError` if there is no current event loop. (Contributed by Kumar Aditya in :gh:`126353`.) + There's a few patterns that use :func:`asyncio.get_event_loop`, most of them can be replaced with :func:`asyncio.run`.