Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
Diff view
5 changes: 5 additions & 0 deletions Lib/asyncio/taskgroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,15 @@ async def _aexit(self, et, exc):
# can be cancelled multiple times if our parent task
# is being cancelled repeatedly (or even once, when
# our own cancellation is already in progress)
pending_cancellation_error = None
while self._tasks:
if self._on_completed_fut is None:
self._on_completed_fut = self._loop.create_future()

try:
await self._on_completed_fut
except exceptions.CancelledError as ex:
pending_cancellation_error = ex
if not self._aborting:
# Our parent task is being cancelled:
#
Expand Down Expand Up @@ -151,6 +153,9 @@ async def _aexit(self, et, exc):
# If there are no pending cancellations left,
# don't propagate CancelledError.
propagate_cancellation_error = None
elif propagate_cancellation_error is None:
# gh-155433: the remaining cancellation is not ours, don't drop it
propagate_cancellation_error = pending_cancellation_error

# Propagate CancelledError if there is one, except if there
# are other errors -- those have priority.
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_asyncio/test_taskgroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,26 @@ async def test_taskgroup_cancel_before_create_task(self):
with self.assertRaises(RuntimeError):
tg.create_task(asyncio.sleep(1))

async def test_taskgroup_cancel_keeps_outer_cancellation(self):
# gh-155433: any cancellation from outside the group must propagate.
async def child():
try:
await asyncio.sleep(10)
finally:
await asyncio.sleep(0.1)

async def body():
async with asyncio.TaskGroup() as tg:
tg.create_task(child())
await asyncio.sleep(0)
tg.cancel()

task = asyncio.create_task(body())
await asyncio.sleep(0.01)
task.cancel()
with self.assertRaises(asyncio.CancelledError):
await task
Comment thread
kumaraditya303 marked this conversation as resolved.
Resolved

async def test_taskgroup_cancel_before_exception(self):
async def raise_exc(parent_tg: asyncio.TaskGroup):
parent_tg.cancel()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :class:`asyncio.TaskGroup` losing outside cancellation after
``cancel()``.
Loading