8000 bpo-37658: Fix asyncio.wait_for() to respect waited task status (GH-2… · python/cpython@6e1954c · GitHub
[go: up one dir, main page]

Skip to content

Commit 6e1954c

Browse files
bpo-37658: Fix asyncio.wait_for() to respect waited task status (GH-21894) (#21965)
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. (cherry picked from commit a2118a1) Co-authored-by: Elvis Pranskevichus <elvis@magic.io>
1 parent 0804539 commit 6e1954c

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
@@ -475,9 +475,12 @@ async def wait_for(fut, timeout, *, loop=None):
475475
try:
476476
await waiter
477477
except exceptions.CancelledError:
478-
fut.remove_done_callback(cb)
479-
fut.cancel()
480-
raise
478+
if fut.done():
479+
return fut.result()
480+
else:
481+
fut.remove_done_callback(cb)
482+
fut.cancel()
483+
raise
481484

482485
if fut.done():
483486
return fut.result()

Lib/test/test_asyncio/test_tasks.py

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

864+
def test_wait_for_cancellation_race_condition(self):
865+
def gen():
866+
yield 0.1
867+
yield 0.1
868+
yield 0.1
869+
yield 0.1
870+
871+
loop = self.new_test_loop(gen)
872+
873+
fut = self.new_future(loop)
874+
loop.call_later(0.1, fut.set_result, "ok")
875+
task = loop.create_task(asyncio.wait_for(fut, timeout=1))
876+
loop.call_later(0.1, task.cancel)
877+
res = loop.run_until_complete(task)
878+
self.assertEqual(res, "ok")
879+
864880
def test_wait_for_waits_for_task_cancellation(self):
865881
loop = asyncio.new_event_loop()
866882
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)
0