Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions Lib/asyncio/taskgroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ def create_task(self, coro, **kwargs):
# the current task too early. gh-128550, gh-128588
self._tasks.add(task)
task.add_done_callback(self._on_task_done)
# gh-155418: an eager task can cancel the group before joining _tasks
if self._aborting and not task.done():
task.cancel()
try:
return task
finally:
Expand Down
14 changes: 14 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,20 @@ async def test_taskgroup_cancel_before_create_task(self):
with self.assertRaises(RuntimeError):
tg.create_task(asyncio.sleep(1))

async def test_taskgroup_cancel_from_child_before_first_suspension(self):
# gh-155418: an eager task can cancel the group before joining _tasks
done = []

async def child(tg):
tg.cancel()
await asyncio.sleep(10)
done.append(True)

async with asyncio.TaskGroup() as tg:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the problem was with the eager task factory?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi! if i understand you well - BaseTestTaskGroup class that stores all of the tests is not inheriting from unittests TestCase https://github.com/deadlovelll/cpython/blob/62ab3f87bdb17aafa97e44fd26386893ead0497b/Lib/test/test_asyncio/test_taskgroups.py#L60.

Runners are TestTaskGroup and TestEagerTaskTaskGroup that inherits from BaseTestTaskGroup and unittest.IsolatedAsyncioTestCase, they are located at the bottom of the file https://github.com/deadlovelll/cpython/blob/62ab3f87bdb17aafa97e44fd26386893ead0497b/Lib/test/test_asyncio/test_taskgroups.py#L1307-L1315

TestEagerTaskTaskGroup already inject eager factory for this

task = tg.create_task(child(tg))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use your reproducer with the print as well? could be useful to catch (instead of print, just use a list and mutate it)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! just pushed the changes

self.assertTrue(task.cancelled())
self.assertEqual(done, [])

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` hang when a task cancels it before
suspending.
Loading