Skip to content

Commit a2118a1

Browse files
authored
bpo-37658: Fix asyncio.wait_for() to respect waited task status (#21894)
Currently, if `asyncio.wait_for()` itself is cancelled it will always raise `CancelledError` regardless if the underlying task is still running. This is similar to a race with the timeout, which is handled already.
1 parent c517fc7 commit a2118a1

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

Lib/asyncio/tasks.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,9 +465,12 @@ async def wait_for(fut, timeout, *, loop=None):
465465
try:
466466
await waiter
467467
except exceptions.CancelledError:
468-
fut.remove_done_callback(cb)
469-
fut.cancel()
470-
raise
468+
if fut.done():
469+
return fut.result()
470+
else:
471+
fut.remove_done_callback(cb)
472+
fut.cancel()
473+
raise
471474

472475
if fut.done():
473476
return fut.result()

Lib/test/test_asyncio/test_tasks.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,22 @@ def gen():
11201120
res = loop.run_until_complete(task)
11211121
self.assertEqual(res, "ok")
11221122

1123+
def test_wait_for_cancellation_race_condition(self):
1124+
def gen():
1125+
yield 0.1
1126+
yield 0.1
1127+
yield 0.1
1128+
yield 0.1
1129+
1130+
loop = self.new_test_loop(gen)
1131+
1132+
fut = self.new_future(loop)
1133+
loop.call_later(0.1, fut.set_result, "ok")
1134+
task = loop.create_task(asyncio.wait_for(fut, timeout=1))
1135+
loop.call_later(0.1, task.cancel)
1136+
res = loop.run_until_complete(task)
1137+
self.assertEqual(res, "ok")
1138+
11231139
def test_wait_for_waits_for_task_cancellation(self):
11241140
loop = asyncio.new_event_loop()
11251141
self.addCleanup(loop.close)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:meth:`asyncio.wait_for` now properly handles races between cancellation of
2+
itself and the completion of the wrapped awaitable.

0 commit comments

Comments
 (0)