Skip to content

Commit ca7ade3

Browse files
Merge remote-tracking branch 'upstream/main' into clinic-groups-inline
2 parents ef7a1d0 + 918fb3a commit ca7ade3

122 files changed

Lines changed: 3351 additions & 1024 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Doc/about.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ and now maintained as an independent project.
1010
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
1111
.. _Sphinx: https://www.sphinx-doc.org/
1212

13-
.. In the online version of these documents, you can submit comments and suggest
13+
.. In the online version of this documentation, you can submit comments and suggest
1414
changes directly on the documentation pages.
1515
1616
Development of the documentation and its toolchain is an entirely volunteer

Doc/c-api/import.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ Importing Modules
146146
alternatives.
147147
148148
.. versionchanged:: 3.15
149-
``__cached__`` is no longer set.
149+
The ``__cached__`` attribute is no longer set.
150150
151151
152152
.. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname)
@@ -170,7 +170,7 @@ Importing Modules
170170
:class:`~importlib.machinery.ModuleSpec` for alternatives.
171171
172172
.. versionchanged:: 3.15
173-
``__cached__`` no longer set.
173+
The ``__cached__`` attribute no longer set.
174174
175175
176176
.. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname)

Doc/library/asyncio-task.rst

Lines changed: 80 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -402,69 +402,85 @@ Example::
402402
task2 = tg.create_task(another_coro(...))
403403
print(f"Both tasks have completed now: {task1.result()}, {task2.result()}")
404404

405-
The ``async with`` statement will wait for all tasks in the group to finish.
406-
While waiting, new tasks may still be added to the group
407-
(for example, by passing ``tg`` into one of the coroutines
408-
and calling ``tg.create_task()`` in that coroutine). There is also opportunity to
409-
request termination of the entire task group with ``tg.cancel()``, based on some condition.
410-
Once the last task has finished and the ``async with`` block is exited,
411-
no new tasks may be added to the group.
412-
413-
The first time any of the tasks belonging to the group fails
414-
with an exception other than :exc:`asyncio.CancelledError`,
415-
the remaining tasks in the group are cancelled.
416-
No further tasks can then be added to the group.
417-
At this point, if the body of the ``async with`` statement is still active
418-
(i.e., :meth:`~object.__aexit__` hasn't been called yet),
419-
the task directly containing the ``async with`` statement is also cancelled.
420-
The resulting :exc:`asyncio.CancelledError` will interrupt an ``await``,
421-
but it will not bubble out of the containing ``async with`` statement.
422-
423-
Once all tasks have finished, if any tasks have failed
424-
with an exception other than :exc:`asyncio.CancelledError`,
425-
those exceptions are combined in an
426-
:exc:`ExceptionGroup` or :exc:`BaseExceptionGroup`
427-
(as appropriate; see their documentation)
428-
which is then raised.
429-
430-
Two base exceptions are treated specially:
431-
If any task fails with :exc:`KeyboardInterrupt` or :exc:`SystemExit`,
432-
the task group still cancels the remaining tasks and waits for them,
433-
but then the initial :exc:`KeyboardInterrupt` or :exc:`SystemExit`
434-
is re-raised instead of :exc:`ExceptionGroup` or :exc:`BaseExceptionGroup`.
435-
436-
If the body of the ``async with`` statement exits with an exception
437-
(so :meth:`~object.__aexit__` is called with an exception set),
438-
this is treated the same as if one of the tasks failed:
439-
the remaining tasks are cancelled and then waited for,
440-
and non-cancellation exceptions are grouped into an
441-
exception group and raised.
442-
The exception passed into :meth:`~object.__aexit__`,
443-
unless it is :exc:`asyncio.CancelledError`,
444-
is also included in the exception group.
445-
The same special case is made for
446-
:exc:`KeyboardInterrupt` and :exc:`SystemExit` as in the previous paragraph.
447-
There is an additional special case made only for the body of the
448-
``async with``: if it raises :exc:`GeneratorExit` and none of the
449-
other tasks raise exceptions that would be reported, then the
450-
:exc:`GeneratorExit` is reraised.
451-
452-
Task groups are careful not to mix up the internal cancellation used to
453-
"wake up" their :meth:`~object.__aexit__` with cancellation requests
454-
for the task in which they are running made by other parties.
405+
A few points to keep in mind when using task groups:
406+
407+
* The ``async with`` statement will wait for all tasks in the group
408+
to finish. While waiting, new tasks may still be added to the group
409+
(for example, by passing ``tg`` into one of the coroutines and
410+
calling ``tg.create_task()`` in that coroutine); once the last task
411+
has finished and the ``async with`` block is exited, no new tasks
412+
may be added.
413+
414+
* Termination of the entire task group may be requested with
415+
``tg.cancel()``, based on some condition.
416+
417+
* If the group is shut down (e.g. because another task failed) before
418+
a newly created task has started running, the task is cancelled
419+
without its coroutine executing at all, not even to its first
420+
``await``. To guarantee that the coroutine starts, create the task
421+
eagerly with ``eager_start=True`` or use
422+
:func:`asyncio.eager_task_factory`. For example::
423+
424+
async def job():
425+
print("job started") # never printed
426+
try:
427+
await asyncio.sleep(1)
428+
finally:
429+
print("job cleaned up") # never printed
430+
431+
async def main():
432+
async with asyncio.TaskGroup() as tg:
433+
tg.create_task(job())
434+
raise RuntimeError # shuts down the group before job() runs
435+
436+
With ``tg.create_task(job(), eager_start=True)``, ``job()`` runs up
437+
to the ``await``, is cancelled there, and both messages are printed.
438+
439+
When any of the tasks belonging to the group fails with an exception
440+
other than :exc:`asyncio.CancelledError` (or the body of the
441+
``async with`` statement exits with an exception, which is treated
442+
the same way):
443+
444+
* The first time this happens, the remaining tasks in the group are
445+
cancelled and then waited for, and no further tasks can be added to
446+
the group. If the body of the ``async with`` statement is still
447+
active (i.e., :meth:`~object.__aexit__` hasn't been called yet),
448+
the task directly containing the ``async with`` statement is also
449+
cancelled. The resulting :exc:`asyncio.CancelledError` will
450+
interrupt an ``await``, but it will not bubble out of the containing
451+
``async with`` statement.
452+
453+
* Once all tasks have finished, the non-cancellation exceptions --
454+
including the exception the body exited with, unless it is
455+
:exc:`asyncio.CancelledError` -- are combined in an
456+
:exc:`ExceptionGroup` or :exc:`BaseExceptionGroup`
457+
(as appropriate; see their documentation), which is then raised.
458+
459+
* Some exceptions are treated specially: if any task fails with
460+
:exc:`KeyboardInterrupt` or :exc:`SystemExit`, the task group still
461+
cancels the remaining tasks and waits for them, but then the initial
462+
:exc:`KeyboardInterrupt` or :exc:`SystemExit` is re-raised instead
463+
of :exc:`ExceptionGroup` or :exc:`BaseExceptionGroup`.
464+
Additionally, if the body of the ``async with`` statement raises
465+
:exc:`GeneratorExit` and none of the other tasks raise exceptions
466+
that would be reported, the :exc:`GeneratorExit` is re-raised.
467+
468+
Task groups are careful not to mix up the internal cancellation used
469+
to "wake up" their :meth:`~object.__aexit__` with cancellation
470+
requests for the task in which they are running made by other parties.
455471
In particular, when one task group is syntactically nested in another,
456-
and both experience an exception in one of their child tasks simultaneously,
457-
the inner task group will process its exceptions, and then the outer task group
458-
will receive another cancellation and process its own exceptions.
472+
and both experience an exception in one of their child tasks
473+
simultaneously, the inner task group will process its exceptions, and
474+
then the outer task group will receive another cancellation and
475+
process its own exceptions.
459476

460477
In the case where a task group is cancelled externally and also must
461478
raise an :exc:`ExceptionGroup`, it will call the parent task's
462-
:meth:`~asyncio.Task.cancel` method. This ensures that a
479+
:meth:`~asyncio.Task.cancel` method. This ensures that a
463480
:exc:`asyncio.CancelledError` will be raised at the next
464-
:keyword:`await`, so the cancellation is not lost.
465-
466-
Task groups preserve the cancellation count
467-
reported by :meth:`asyncio.Task.cancelling`.
481+
:keyword:`await`, so the cancellation is not lost. Task groups also
482+
preserve the cancellation count reported by
483+
:meth:`asyncio.Task.cancelling`.
468484

469485
.. versionchanged:: 3.13
470486

@@ -843,17 +859,13 @@ Timeouts
843859
Wait for the *fut* :ref:`awaitable <asyncio-awaitables>`
844860
to complete with a timeout.
845861

846-
If *fut* is a coroutine it is automatically scheduled as a Task.
847-
848862
*timeout* can either be ``None`` or a float or int number of seconds
849863
to wait for. If *timeout* is ``None``, block until the future
850864
completes.
851865

852-
If a timeout occurs, it cancels the task and raises
853-
:exc:`TimeoutError`.
866+
If a timeout occurs, it cancels *fut* and raises :exc:`TimeoutError`.
854867

855-
To avoid the task :meth:`cancellation <Task.cancel>`,
856-
wrap it in :func:`shield`.
868+
To prevent *fut* from being cancelled, wrap it in :func:`shield`.
857869

858870
The function will wait until the future is actually cancelled,
859871
so the total wait time may exceed the *timeout*. If an exception
@@ -894,6 +906,10 @@ Timeouts
894906
.. versionchanged:: 3.11
895907
Raises :exc:`TimeoutError` instead of :exc:`asyncio.TimeoutError`.
896908

909+
.. versionchanged:: 3.12
910+
Implemented using :func:`asyncio.timeout`, a coroutine passed as *fut*
911+
is no longer wrapped in a :class:`Task` when *timeout* is positive.
912+
897913

898914
Waiting primitives
899915
==================

0 commit comments

Comments
 (0)