]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-124594: Create and reuse the same context for the entire asyncio REPL session...
authorBartosz Sławecki <bartoszpiotrslawecki@gmail.com>
Tue, 1 Oct 2024 14:17:22 +0000 (16:17 +0200)
committerGitHub <noreply@github.com>
Tue, 1 Oct 2024 14:17:22 +0000 (14:17 +0000)
Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
Lib/asyncio/__main__.py
Lib/test/test_repl.py
Misc/NEWS.d/next/Library/2024-09-26-13-43-39.gh-issue-124594.peYhsP.rst [new file with mode: 0644]

index 5120140e061691b5dc69939c087576522ca4a705..95c636f9e028665523b639d01e9151c0af7cc5f7 100644 (file)
@@ -1,6 +1,7 @@
 import ast
 import asyncio
 import concurrent.futures
+import contextvars
 import inspect
 import os
 import site
@@ -22,6 +23,7 @@ class AsyncIOInteractiveConsole(InteractiveColoredConsole):
         self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
 
         self.loop = loop
+        self.context = contextvars.copy_context()
 
     def runcode(self, code):
         global return_code
@@ -55,12 +57,12 @@ class AsyncIOInteractiveConsole(InteractiveColoredConsole):
                 return
 
             try:
-                repl_future = self.loop.create_task(coro)
+                repl_future = self.loop.create_task(coro, context=self.context)
                 futures._chain_future(repl_future, future)
             except BaseException as exc:
                 future.set_exception(exc)
 
-        loop.call_soon_threadsafe(callback)
+        loop.call_soon_threadsafe(callback, context=self.context)
 
         try:
             return future.result()
index 7a7285a1a2fcfd4a9c6ead7f460ebb25c13a58c7..e764e60560db2340fa2eb9ec46958f2402e8c80e 100644 (file)
@@ -291,5 +291,42 @@ class TestInteractiveModeSyntaxErrors(unittest.TestCase):
         self.assertEqual(traceback_lines, expected_lines)
 
 
+class TestAsyncioREPLContextVars(unittest.TestCase):
+    def test_toplevel_contextvars_sync(self):
+        user_input = dedent("""\
+        from contextvars import ContextVar
+        var = ContextVar("var", default="failed")
+        var.set("ok")
+        """)
+        p = spawn_repl("-m", "asyncio")
+        p.stdin.write(user_input)
+        user_input2 = dedent("""
+        print(f"toplevel contextvar test: {var.get()}")
+        """)
+        p.stdin.write(user_input2)
+        output = kill_python(p)
+        self.assertEqual(p.returncode, 0)
+        expected = "toplevel contextvar test: ok"
+        self.assertIn(expected, output, expected)
+
+    def test_toplevel_contextvars_async(self):
+        user_input = dedent("""\
+        from contextvars import ContextVar
+        var = ContextVar('var', default='failed')
+        """)
+        p = spawn_repl("-m", "asyncio")
+        p.stdin.write(user_input)
+        user_input2 = "async def set_var(): var.set('ok')\n"
+        p.stdin.write(user_input2)
+        user_input3 = "await set_var()\n"
+        p.stdin.write(user_input3)
+        user_input4 = "print(f'toplevel contextvar test: {var.get()}')\n"
+        p.stdin.write(user_input4)
+        output = kill_python(p)
+        self.assertEqual(p.returncode, 0)
+        expected = "toplevel contextvar test: ok"
+        self.assertIn(expected, output, expected)
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2024-09-26-13-43-39.gh-issue-124594.peYhsP.rst b/Misc/NEWS.d/next/Library/2024-09-26-13-43-39.gh-issue-124594.peYhsP.rst
new file mode 100644 (file)
index 0000000..ac48bd8
--- /dev/null
@@ -0,0 +1 @@
+All :mod:`asyncio` REPL prompts run in the same :class:`context <contextvars.Context>`. Contributed by Bartosz Sławecki.