mirror of
https://github.com/python/cpython.git
synced 2025-10-02 21:25:24 +00:00
[3.13] gh-124594: Create and reuse the same context for the entire asyncio REPL session (GH-124595) (#124848)
gh-124594: Create and reuse the same context for the entire asyncio REPL session (GH-124595)
(cherry picked from commit 67e01a430f
)
Co-authored-by: Bartosz Sławecki <bartoszpiotrslawecki@gmail.com>
Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
This commit is contained in:
parent
8cf646adea
commit
35d9624109
3 changed files with 42 additions and 2 deletions
|
@ -1,6 +1,7 @@
|
||||||
import ast
|
import ast
|
||||||
import asyncio
|
import asyncio
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
|
import contextvars
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
import site
|
import site
|
||||||
|
@ -22,6 +23,7 @@ class AsyncIOInteractiveConsole(InteractiveColoredConsole):
|
||||||
self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
|
self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
|
||||||
|
|
||||||
self.loop = loop
|
self.loop = loop
|
||||||
|
self.context = contextvars.copy_context()
|
||||||
|
|
||||||
def runcode(self, code):
|
def runcode(self, code):
|
||||||
global return_code
|
global return_code
|
||||||
|
@ -55,12 +57,12 @@ class AsyncIOInteractiveConsole(InteractiveColoredConsole):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
repl_future = self.loop.create_task(coro)
|
repl_future = self.loop.create_task(coro, context=self.context)
|
||||||
futures._chain_future(repl_future, future)
|
futures._chain_future(repl_future, future)
|
||||||
except BaseException as exc:
|
except BaseException as exc:
|
||||||
future.set_exception(exc)
|
future.set_exception(exc)
|
||||||
|
|
||||||
loop.call_soon_threadsafe(callback)
|
loop.call_soon_threadsafe(callback, context=self.context)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return future.result()
|
return future.result()
|
||||||
|
|
|
@ -291,5 +291,42 @@ class TestInteractiveModeSyntaxErrors(unittest.TestCase):
|
||||||
self.assertEqual(traceback_lines, expected_lines)
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
All :mod:`asyncio` REPL prompts run in the same :class:`context <contextvars.Context>`. Contributed by Bartosz Sławecki.
|
Loading…
Add table
Add a link
Reference in a new issue