8000 bpo-47062: Implement asyncio.Runner context manager by asvetlov · Pull Request #31799 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-47062: Implement asyncio.Runner context manager #31799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
61f10d0
Implement Runner class
asvetlov Mar 9, 2022
d471799
Add get_loop() / new_loop() methods
asvetlov Mar 10, 2022
c68ba85
Clarify
asvetlov Mar 10, 2022
d530481
Add tests
asvetlov Mar 10, 2022
6ee7c9a
Add a comment
asvetlov Mar 10, 2022
e15d70b
Adopt IsolatedAsyncioTestCase to use Runner
asvetlov Mar 10, 2022
5c7a669
Merge branch 'main' into asyncio-runner
asvetlov Mar 10, 2022
d41988d
Merge branch 'main' into asyncio-runner
asvetlov Mar 10, 2022
8014227
Add docs sketch
asvetlov Mar 12, 2022
98e39db
Merge branch 'main' into asyncio-runner
asvetlov Mar 14, 2022
98e7a22
Add context arg to Runner.run()
asvetlov Mar 14, 2022
f4cd673
Work on docs
asvetlov Mar 17, 2022
1764045
Merge branch 'main' into asyncio-runner
asvetlov Mar 18, 2022
a443b37
Work on
asvetlov Mar 18, 2022
e6be8f7
Improve docs
asvetlov Mar 18, 2022
b1dfe4f
Add NEWS
asvetlov Mar 18, 2022
759f72a
Drop not related file
asvetlov Mar 18, 2022
f47d66a
Fix doc
asvetlov Mar 18, 2022
546440b
Update Lib/asyncio/runners.py
asvetlov Mar 18, 2022
6935f7d
Update Doc/library/asyncio-runner.rst
asvetlov Mar 18, 2022
9b9a004
Update Lib/asyncio/runners.py
asvetlov Mar 18, 2022
b0c5b8c
Improve wording
asvetlov Mar 19, 2022
599c9db
Add a test for double 'with' usage
asvetlov Mar 19, 2022
b0da74b
Improve tests
asvetlov Mar 19, 2022
04cfff9
Work on
asvetlov Mar 22, 2022
8753465
Merge branch 'main' into asyncio-runner
asvetlov Mar 22, 2022
674ad4e
Lazy init version
asvetlov Mar 22, 2022
7cd5430
Tune
asvetlov Mar 22, 2022
dd28ef7
Drop explicit get_context() function, asyncio.Task has no it also
asvetlov Mar 23, 2022
5e13b2e
Add docs for .close() method
asvetlov Mar 23, 2022
c0b999d
Add better error message for recursive run() call
asvetlov Mar 24, 2022
4937cd0
Add a note
asvetlov Mar 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Prev Previous commit
Next Next commit
Work on
  • Loading branch information
asvetlov committed Mar 18, 2022
commit a443b3799bcb820ad2018655f69ecc8ac4525a3d
38 changes: 23 additions & 15 deletions Doc/library/asyncio-runner.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,39 @@ Runner

------------------------------------

*Runner* context manager is used for two purposes:

1. Providing a primitive for event loop initialization and finalization with correct
resources cleanup (cancelling background tasks, shutdowning the default thread-pool
executor and pending async generators, etc.)
:func:`asyncio.run` provides a convinient very high-level API for running asyncio code.

2. Processing *context variables* between async function calls.
It is the preferred approach that satisfies almost all use cases.

:func:`asyncio.run` is used for running asyncio code usually, but sometimes several
top-level async calls are needed in the same loop and context instead of the
single ``main()`` call provided by :func:`asyncio.run`.
Sometimes several top-level async calls are needed in the same loop and contextvars
context instead of the single ``main()`` call provided by :func:`asyncio.run`.

For example, there is a synchronous unittest library or console framework that should
work with async code.

A code that The following examples are equal:
The *Runner* context manager can be used for such things:

.. code:: python

async def main():
...
with asyncio.Runner() as runner:
runner.run(func1())
runner.run(func2())

On the :class:`~asyncio.Runner` instantiation the new event loop is created.

All :meth:`~asyncio.Runner.run` calls share the same :class:`~contextvars.Context` and
internal :class:`~asyncio.l 10000 oop`.

On the exit of :keyword:`with` block all background tasks are cancelled, the embedded
loop is closing.


.. class:: Runner(*, debug=None, factory=None)




asyncio.run(main())


enter
Usually,

.. rubric:: Preface
Expand Down
17 changes: 15 additions & 2 deletions Lib/asyncio/runners.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
__all__ = ('Runner', 'run')

import contextvars
from . import coroutines
from . import events
from . import tasks
Expand Down Expand Up @@ -30,10 +31,14 @@ class Runner:
asyncio.run() call doesn't work.

"""
def __init__(self, *, debug=None, factory=events.new_event_loop):
self._loop = factory()
def __init__(self, *, debug=None, factory=None):
if factory is None:
self._loop = events.new_event_loop()
else:
self._loop = factory()
if debug is not None:
self._loop.set_debug(debug)
self._context = contextvars.copy_context()

def __enter__(self):
return self
Expand All @@ -59,13 +64,21 @@ def run(self, coro, *, context=None):
if not coroutines.iscoroutine(coro):
raise ValueError("a coroutine was expected, got {!r}".format(coro))

if self._loop is None:
raise RuntimeError("Runner is closed")

if context is None:
context = self._context
task = self._loop.create_task(coro, context=context)
return self._loop.run_until_complete(task)

def get_loop(self):
"""Returnb embedded event loop."""
return self._loop

def get_context(self):
return self._context.copy()


def run(main, *, debug=None):
"""Execute the coroutine and return the result.
Expand Down
0