mirror of
https://github.com/python/cpython.git
synced 2025-09-27 10:50:04 +00:00
bpo-32751: Wait for task cancel in asyncio.wait_for() when timeout <= 0 (GH-21895) (GH-21963)
When I was fixing bpo-32751 back in GH-7216 I missed the case when
*timeout* is zero or negative. This takes care of that.
Props to @aaliddell for noticing the inconsistency.
(cherry picked from commit c517fc7121
)
Co-authored-by: Elvis Pranskevichus <elvis@magic.io>
This commit is contained in:
parent
d7cd1164c1
commit
1036ccb55d
3 changed files with 41 additions and 2 deletions
|
@ -445,7 +445,12 @@ async def wait_for(fut, timeout, *, loop=None):
|
||||||
if fut.done():
|
if fut.done():
|
||||||
return fut.result()
|
return fut.result()
|
||||||
|
|
||||||
fut.cancel()
|
await _cancel_and_wait(fut, loop=loop)
|
||||||
|
try:
|
||||||
|
fut.result()
|
||||||
|
except exceptions.CancelledError as exc:
|
||||||
|
raise exceptions.TimeoutError() from exc
|
||||||
|
else:
|
||||||
raise exceptions.TimeoutError()
|
raise exceptions.TimeoutError()
|
||||||
|
|
||||||
waiter = loop.create_future()
|
waiter = loop.create_future()
|
||||||
|
|
|
@ -1131,6 +1131,9 @@ class BaseTaskTests:
|
||||||
nonlocal task_done
|
nonlocal task_done
|
||||||
try:
|
try:
|
||||||
await asyncio.sleep(0.2)
|
await asyncio.sleep(0.2)
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
await asyncio.sleep(_EPSILON)
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
task_done = True
|
task_done = True
|
||||||
|
|
||||||
|
@ -1145,6 +1148,34 @@ class BaseTaskTests:
|
||||||
chained = cm.exception.__context__
|
chained = cm.exception.__context__
|
||||||
self.assertEqual(type(chained), asyncio.CancelledError)
|
self.assertEqual(type(chained), asyncio.CancelledError)
|
||||||
|
|
||||||
|
def test_wait_for_waits_for_task_cancellation_w_timeout_0(self):
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
self.addCleanup(loop.close)
|
||||||
|
|
||||||
|
task_done = False
|
||||||
|
|
||||||
|
async def foo():
|
||||||
|
async def inner():
|
||||||
|
nonlocal task_done
|
||||||
|
try:
|
||||||
|
await asyncio.sleep(10)
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
await asyncio.sleep(_EPSILON)
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
task_done = True
|
||||||
|
|
||||||
|
inner_task = self.new_task(loop, inner())
|
||||||
|
await asyncio.sleep(_EPSILON)
|
||||||
|
await asyncio.wait_for(inner_task, timeout=0)
|
||||||
|
|
||||||
|
with self.assertRaises(asyncio.TimeoutError) as cm:
|
||||||
|
loop.run_until_complete(foo())
|
||||||
|
|
||||||
|
self.assertTrue(task_done)
|
||||||
|
chained = cm.exception.__context__
|
||||||
|
self.assertEqual(type(chained), asyncio.CancelledError)
|
||||||
|
|
||||||
def test_wait_for_reraises_exception_during_cancellation(self):
|
def test_wait_for_reraises_exception_during_cancellation(self):
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
self.addCleanup(loop.close)
|
self.addCleanup(loop.close)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
When cancelling the task due to a timeout, :meth:`asyncio.wait_for` will now
|
||||||
|
wait until the cancellation is complete also in the case when *timeout* is
|
||||||
|
<= 0, like it does with positive timeouts.
|
Loading…
Add table
Add a link
Reference in a new issue