From 92f629bded7155c96f98ba585aaa607c52f7affc Mon Sep 17 00:00:00 2001 From: johnslavik Date: Tue, 16 Dec 2025 04:36:36 +0100 Subject: [PATCH 01/10] Employ `asyncio.Runner` in the asyncio REPL --- Lib/asyncio/__main__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index d078ebfa4cedbe..60406b15f50886 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -187,8 +187,8 @@ def interrupt(self) -> None: from _pyrepl.main import CAN_USE_PYREPL return_code = 0 - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) + runner = asyncio.Runner() + loop = runner.get_loop() repl_locals = {'asyncio': asyncio} for key in {'__name__', '__package__', @@ -240,4 +240,5 @@ def interrupt(self) -> None: break console.write('exiting asyncio REPL...\n') + runner.close() sys.exit(return_code) From 95cc73a38707eb7755ae41e626461bc03c3c2a39 Mon Sep 17 00:00:00 2001 From: johnslavik Date: Tue, 16 Dec 2025 04:39:35 +0100 Subject: [PATCH 02/10] Add news entry --- .../next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst new file mode 100644 index 00000000000000..07f5a69535545e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst @@ -0,0 +1,2 @@ +The asyncio REPL now properly closes the loop upon the end of session. +Contributed by Bartosz Sławecki. From ac134b19fed4698dc9b607efdcc3fe20474b210e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Tue, 16 Dec 2025 17:57:10 +0100 Subject: [PATCH 03/10] Better wording in the news entry --- .../Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst index 07f5a69535545e..0bb7640a3b23b1 100644 --- a/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst +++ b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst @@ -1,2 +1,3 @@ -The asyncio REPL now properly closes the loop upon the end of session. +The asyncio REPL now properly closes the loop upon the end of interactive session. +Previously, it could cause surprising warnings. Contributed by Bartosz Sławecki. From 9cbbf214bc603ce5f4737db75b17f1c0ee699d9a Mon Sep 17 00:00:00 2001 From: johnslavik Date: Thu, 18 Dec 2025 12:17:59 +0100 Subject: [PATCH 04/10] Revert "Employ `asyncio.Runner` in the asyncio REPL" This reverts commit 92f629bded7155c96f98ba585aaa607c52f7affc. --- Lib/asyncio/__main__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 60406b15f50886..d078ebfa4cedbe 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -187,8 +187,8 @@ def interrupt(self) -> None: from _pyrepl.main import CAN_USE_PYREPL return_code = 0 - runner = asyncio.Runner() - loop = runner.get_loop() + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) repl_locals = {'asyncio': asyncio} for key in {'__name__', '__package__', @@ -240,5 +240,4 @@ def interrupt(self) -> None: break console.write('exiting asyncio REPL...\n') - runner.close() sys.exit(return_code) From 46396002957458a83dd37e8f1d6dcad2d5216401 Mon Sep 17 00:00:00 2001 From: johnslavik Date: Thu, 18 Dec 2025 12:19:21 +0100 Subject: [PATCH 05/10] Call `.stop()` on the event loop when the asyncio REPL exits --- Lib/asyncio/__main__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index d078ebfa4cedbe..44030f564daf64 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -239,5 +239,6 @@ def interrupt(self) -> None: else: break + loop.close() console.write('exiting asyncio REPL...\n') sys.exit(return_code) From d3f670d6d16b5cd1d92c1b3a012359c576ebad1b Mon Sep 17 00:00:00 2001 From: johnslavik Date: Thu, 18 Dec 2025 12:56:21 +0100 Subject: [PATCH 06/10] Add test to check asyncio REPL closes the loop --- Lib/test/test_repl.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 042aa84b35dcf8..36522be503fd7c 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -409,6 +409,20 @@ def test_toplevel_contextvars_async(self): expected = "toplevel contextvar test: ok" self.assertIn(expected, output, expected) + def test_loop_was_closed(self): + user_input = dedent("""\ + import atexit + atexit.register(\ + lambda loop: print("loop closed:", loop.is_closed()),\ + asyncio.get_running_loop(),\ + ) + """) + p = spawn_asyncio_repl() + p.stdin.write(user_input) + output = kill_python(p) + self.assertEqual(p.returncode, 0) + self.assertIn("loop closed: True", output) + if __name__ == "__main__": unittest.main() From 8b0824a48f87ddd44a012346b31696d864641d3d Mon Sep 17 00:00:00 2001 From: johnslavik Date: Thu, 18 Dec 2025 13:12:32 +0100 Subject: [PATCH 07/10] Better test name --- Lib/test/test_repl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 36522be503fd7c..440dc000a99762 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -409,7 +409,7 @@ def test_toplevel_contextvars_async(self): expected = "toplevel contextvar test: ok" self.assertIn(expected, output, expected) - def test_loop_was_closed(self): + def test_loop_closed_after_exit(self): user_input = dedent("""\ import atexit atexit.register(\ From f5031b0311b78f27c00eed5d6469abbd1204d378 Mon Sep 17 00:00:00 2001 From: johnslavik Date: Thu, 18 Dec 2025 13:15:42 +0100 Subject: [PATCH 08/10] Move `loop.close()` below console log in present continuous tense --- Lib/asyncio/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 44030f564daf64..89d456b6858c07 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -239,6 +239,6 @@ def interrupt(self) -> None: else: break - loop.close() console.write('exiting asyncio REPL...\n') + loop.close() sys.exit(return_code) From 5e45253273e77f86ad5c4e86004ae3cdf20355d6 Mon Sep 17 00:00:00 2001 From: johnslavik Date: Thu, 18 Dec 2025 13:27:25 +0100 Subject: [PATCH 09/10] Remove test --- Lib/test/test_repl.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 440dc000a99762..042aa84b35dcf8 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -409,20 +409,6 @@ def test_toplevel_contextvars_async(self): expected = "toplevel contextvar test: ok" self.assertIn(expected, output, expected) - def test_loop_closed_after_exit(self): - user_input = dedent("""\ - import atexit - atexit.register(\ - lambda loop: print("loop closed:", loop.is_closed()),\ - asyncio.get_running_loop(),\ - ) - """) - p = spawn_asyncio_repl() - p.stdin.write(user_input) - output = kill_python(p) - self.assertEqual(p.returncode, 0) - self.assertIn("loop closed: True", output) - if __name__ == "__main__": unittest.main() From c5566abbd8a4ca918d28d6fa1310d357b28ec1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Thu, 18 Dec 2025 13:29:30 +0100 Subject: [PATCH 10/10] Use a crossref to asyncio in the news entry Co-authored-by: Kumar Aditya --- .../next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst index 0bb7640a3b23b1..92a723cbc29739 100644 --- a/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst +++ b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst @@ -1,3 +1,3 @@ -The asyncio REPL now properly closes the loop upon the end of interactive session. +The :mod:`asyncio` REPL now properly closes the loop upon the end of interactive session. Previously, it could cause surprising warnings. Contributed by Bartosz Sławecki.