Message414988
Now asyncio creates a new context copy on task creation.
It is the perfect behavior *by default* and should stay as is.
However, sometimes passing an explicit context into a task and using back the context modified by task code is desired.
The most obvious use-case is testing: both unittest and pytest have multi-phase test initialization (asyncSetUp() methods and async fixtures correspondingly). If asyncSetUp() updates context variable -- test code expects to see this change.
Currently, unittest runs the setup-test-cleanup chain in a single task and uses an internal queue to push a new coroutine for execution and get results back. It works but is cumbersome.
Another solution is to create a task per test execution step and wrap the task creation with Context.run(). The problem is in getting the updated context back. A task creates a context copy on starting, thus the modified context is stored in the task internal attribute only. To get it back a trampoline async function should be used, e.g.
async def wrapper(coro):
try:
return await coro
finally:
context = contextvars.copy_context()
# store the context copy somewhere
Again, it looks more complicated as it should be.
The proposal is:
1. Add 'context' keyword-only argument to asyncio.create_task() and loop.create_task().
2. Use this context if explicitly passed, create a copy of the current context otherwise.
The proposal is backward-compatible. Low-level API (call_soon(), call_later() etc.) already accept 'context' argument.
The attached PR demonstrates how the proposed API simplifies unittest.IsolatedAsyncioTestCase internals. |
|
Date |
User |
Action |
Args |
2022-03-12 10:33:08 | asvetlov | set | recipients:
+ asvetlov, yselivanov |
2022-03-12 10:33:08 | asvetlov | set | messageid: <1647081188.22.0.709370904314.issue46994@roundup.psfhosted.org> |
2022-03-12 10:33:08 | asvetlov | link | issue46994 messages |
2022-03-12 10:33:08 | asvetlov | create | |
|