Closes #23219: cancelling asyncio.wait_for() now cancels the task

This commit is contained in:
Victor Stinner 2015-01-15 16:29:10 +01:00
parent ab8848bc2a
commit 922bc2ca12
2 changed files with 35 additions and 4 deletions

View file

@ -347,10 +347,9 @@ def wait_for(fut, timeout, *, loop=None):
it cancels the task and raises TimeoutError. To avoid the task it cancels the task and raises TimeoutError. To avoid the task
cancellation, wrap it in shield(). cancellation, wrap it in shield().
Usage: If the wait is cancelled, the task is also cancelled.
result = yield from asyncio.wait_for(fut, 10.0)
This function is a coroutine.
""" """
if loop is None: if loop is None:
loop = events.get_event_loop() loop = events.get_event_loop()
@ -367,7 +366,12 @@ def wait_for(fut, timeout, *, loop=None):
try: try:
# wait until the future completes or the timeout # wait until the future completes or the timeout
try:
yield from waiter yield from waiter
except futures.CancelledError:
fut.remove_done_callback(cb)
fut.cancel()
raise
if fut.done(): if fut.done():
return fut.result() return fut.result()

View file

@ -1705,6 +1705,33 @@ class TaskTests(test_utils.TestCase):
'test_task_source_traceback')) 'test_task_source_traceback'))
self.loop.run_until_complete(task) self.loop.run_until_complete(task)
def _test_cancel_wait_for(self, timeout):
loop = asyncio.new_event_loop()
self.addCleanup(loop.close)
@asyncio.coroutine
def blocking_coroutine():
fut = asyncio.Future(loop=loop)
# Block: fut result is never set
yield from fut
task = loop.create_task(blocking_coroutine())
wait = loop.create_task(asyncio.wait_for(task, timeout, loop=loop))
loop.call_soon(wait.cancel)
self.assertRaises(asyncio.CancelledError,
loop.run_until_complete, wait)
# Python issue #23219: cancelling the wait must also cancel the task
self.assertTrue(task.cancelled())
def test_cancel_blocking_wait_for(self):
self._test_cancel_wait_for(None)
def test_cancel_wait_for(self):
self._test_cancel_wait_for(60.0)
class GatherTestsBase: class GatherTestsBase: