bpo-32751: Wait for task cancel in asyncio.wait_for() when timeout <=… · python/cpython@c517fc7 (original) (raw)

3 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -445,8 +445,13 @@ async def wait_for(fut, timeout, *, loop=None):
445 445 if fut.done():
446 446 return fut.result()
447 447
448 -fut.cancel()
449 -raise exceptions.TimeoutError()
448 +await _cancel_and_wait(fut, loop=loop)
449 +try:
450 +fut.result()
451 +except exceptions.CancelledError as exc:
452 +raise exceptions.TimeoutError() from exc
453 +else:
454 +raise exceptions.TimeoutError()
450 455
451 456 waiter = loop.create_future()
452 457 timeout_handle = loop.call_later(timeout, _release_waiter, waiter)
Original file line number Diff line number Diff line change
@@ -1131,6 +1131,9 @@ async def inner():
1131 1131 nonlocal task_done
1132 1132 try:
1133 1133 await asyncio.sleep(0.2)
1134 +except asyncio.CancelledError:
1135 +await asyncio.sleep(_EPSILON)
1136 +raise
1134 1137 finally:
1135 1138 task_done = True
1136 1139
@@ -1145,6 +1148,34 @@ async def inner():
1145 1148 chained = cm.exception.__context__
1146 1149 self.assertEqual(type(chained), asyncio.CancelledError)
1147 1150
1151 +def test_wait_for_waits_for_task_cancellation_w_timeout_0(self):
1152 +loop = asyncio.new_event_loop()
1153 +self.addCleanup(loop.close)
1154 +
1155 +task_done = False
1156 +
1157 +async def foo():
1158 +async def inner():
1159 +nonlocal task_done
1160 +try:
1161 +await asyncio.sleep(10)
1162 +except asyncio.CancelledError:
1163 +await asyncio.sleep(_EPSILON)
1164 +raise
1165 +finally:
1166 +task_done = True
1167 +
1168 +inner_task = self.new_task(loop, inner())
1169 +await asyncio.sleep(_EPSILON)
1170 +await asyncio.wait_for(inner_task, timeout=0)
1171 +
1172 +with self.assertRaises(asyncio.TimeoutError) as cm:
1173 +loop.run_until_complete(foo())
1174 +
1175 +self.assertTrue(task_done)
1176 +chained = cm.exception.__context__
1177 +self.assertEqual(type(chained), asyncio.CancelledError)
1178 +
1148 1179 def test_wait_for_reraises_exception_during_cancellation(self):
1149 1180 loop = asyncio.new_event_loop()
1150 1181 self.addCleanup(loop.close)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1 +When cancelling the task due to a timeout, :meth:`asyncio.wait_for` will now
2 +wait until the cancellation is complete also in the case when *timeout* is
3 +<= 0, like it does with positive timeouts.