Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32.3k
gh-108951: add TaskGroup.cancel()#127214
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading.Please reload this page.
Changes from1 commit
8ec2f60
907f1d0
2cfa1e6
bce1fb1
7754aad
452042d
f077241
8345647
7235c20
243db79
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
ISSUE:#108951
- Loading branch information
Uh oh!
There was an error while loading.Please reload this page.
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -342,6 +342,25 @@ and reliable way to wait for all tasks in the group to finish. | ||
Close the given coroutine if the task group is not active. | ||
.. method:: stop() | ||
Stop the task group | ||
:meth:`~asyncio.Task.cancel` will be called on any tasks in the group that | ||
aren't yet done, as well as the parent (body) of the group. This will | ||
cause the task group context manager to exit *without* a | ||
:exc:`asyncio.CancelledError` being raised. | ||
If :meth:`stop` is called before entering the task group, the group will be | ||
stopped upon entry. This is useful for patterns where one piece of | ||
code passes an unused TaskGroup instance to another in order to have | ||
the ability to stop anything run within the group. | ||
:meth:`stop` is idempotent and may be called after the task group has | ||
already exited. | ||
.. versionadded:: 3.14 | ||
belm0 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
Example:: | ||
async def main(): | ||
@@ -414,53 +433,6 @@ reported by :meth:`asyncio.Task.cancelling`. | ||
Improved handling of simultaneous internal and external cancellations | ||
and correct preservation of cancellation counts. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. These docs make sense for older versions. Contributor
| ||
Sleeping | ||
======== | ||
ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. copying comment from@graingert (please make all comments on the code so that there can be a thread and Resolve button)
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -3,10 +3,12 @@ | ||
import sys | ||
import gc | ||
belm0 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
import asyncio | ||
import contextvars | ||
import contextlib | ||
from asyncio import taskgroups | ||
import math | ||
import unittest | ||
import warnings | ||
@@ -997,6 +999,69 @@ class MyKeyboardInterrupt(KeyboardInterrupt): | ||
self.assertIsNotNone(exc) | ||
self.assertListEqual(gc.get_referrers(exc), no_other_refs()) | ||
async def test_taskgroup_stop_children(self): | ||
belm0 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
async with asyncio.TaskGroup() as tg: | ||
tg.create_task(asyncio.sleep(math.inf)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Maybe these tasks should look like this? asyncdeftask(results,num):results.append(num)awaitasyncio.sleep(math.inf)results.append(-num) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. So we can assert what was in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. For this particular test, I chose a different test approach, which is to wrap in For the other tests using | ||
tg.create_task(asyncio.sleep(math.inf)) | ||
await asyncio.sleep(0) | ||
tg.stop() | ||
async def test_taskgroup_stop_body(self): | ||
count = 0 | ||
async with asyncio.TaskGroup() as tg: | ||
tg.stop() | ||
count += 1 | ||
await asyncio.sleep(0) | ||
count += 1 | ||
self.assertEqual(count, 1) | ||
async def test_taskgroup_stop_idempotent(self): | ||
count = 0 | ||
async with asyncio.TaskGroup() as tg: | ||
tg.stop() | ||
tg.stop() | ||
count += 1 | ||
await asyncio.sleep(0) | ||
count += 1 | ||
self.assertEqual(count, 1) | ||
async def test_taskgroup_stop_after_exit(self): | ||
async with asyncio.TaskGroup() as tg: | ||
await asyncio.sleep(0) | ||
tg.stop() | ||
async def test_taskgroup_stop_before_enter(self): | ||
tg = asyncio.TaskGroup() | ||
tg.stop() | ||
count = 0 | ||
async with tg: | ||
count += 1 | ||
await asyncio.sleep(0) | ||
count += 1 | ||
self.assertEqual(count, 1) | ||
async def test_taskgroup_stop_before_exception(self): | ||
async def raise_exc(parent_tg: asyncio.TaskGroup): | ||
parent_tg.stop() | ||
raise RuntimeError | ||
with self.assertRaises(ExceptionGroup): | ||
async with asyncio.TaskGroup() as tg: | ||
tg.create_task(raise_exc(tg)) | ||
await asyncio.sleep(1) | ||
async def test_taskgroup_stop_after_exception(self): | ||
async def raise_exc(parent_tg: asyncio.TaskGroup): | ||
try: | ||
raise RuntimeError | ||
finally: | ||
parent_tg.stop() | ||
with self.assertRaises(ExceptionGroup): | ||
async with asyncio.TaskGroup() as tg: | ||
tg.create_task(raise_exc(tg)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. What will happen if some tasks cancels itself? How would this interact with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Do you mean the case where a child task calls There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Cancellations (and thus taskgroup stops) happen when the next | ||
await asyncio.sleep(1) | ||
if __name__ == "__main__": | ||
unittest.main() |
Uh oh!
There was an error while loading.Please reload this page.