From: INADA Naoki Date: Fri, 12 May 2017 05:34:40 +0000 (+0900) Subject: bpo-30048: asyncio: fix Task.cancel() was ignored. (GH-1547) X-Git-Tag: v3.5.4rc1~157 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e94dedcddf5e09164bf20f18a3c701eeb96c71e;p=python bpo-30048: asyncio: fix Task.cancel() was ignored. (GH-1547) * bpo-30048: asyncio: fix Task.cancel() was ignored. (GH-1097) when there are no more `await` or `yield (from)` before return in coroutine, cancel was ignored. example: async def coro(): asyncio.Task.current_task().cancel() return 42 ... res = await coro() # should raise CancelledError (cherry picked from commit 991adca012f5e106c2d4040ce619c696ba6f9c46) * fix test --- diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index b6bd53cef1..89d0989c61 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -240,7 +240,12 @@ class Task(futures.Future): else: result = coro.throw(exc) except StopIteration as exc: - self.set_result(exc.value) + if self._must_cancel: + # Task is cancelled right before coro stops. + self._must_cancel = False + self.set_exception(futures.CancelledError()) + else: + self.set_result(exc.value) except futures.CancelledError: super().cancel() # I.e., Future.cancel(self). except Exception as exc: diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 9872926739..b3d0653e82 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -573,6 +573,24 @@ class TaskTests(test_utils.TestCase): self.assertFalse(t._must_cancel) # White-box test. self.assertFalse(t.cancel()) + def test_cancel_at_end(self): + """coroutine end right after task is cancelled""" + loop = asyncio.new_event_loop() + self.set_event_loop(loop) + + @asyncio.coroutine + def task(): + t.cancel() + self.assertTrue(t._must_cancel) # White-box test. + return 12 + + t = asyncio.Task(task(), loop=loop) + self.assertRaises( + asyncio.CancelledError, loop.run_until_complete, t) + self.assertTrue(t.done()) + self.assertFalse(t._must_cancel) # White-box test. + self.assertFalse(t.cancel()) + def test_stop_while_run_in_complete(self): def gen(): diff --git a/Misc/NEWS b/Misc/NEWS index 889386dba0..41fe80f44c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ Extension Modules Library ------- +- bpo-30048: Fixed ``Task.cancel()`` can be ignored when the task is + running coroutine and the coroutine returned without any more ``await``. + - bpo-29990: Fix range checking in GB18030 decoder. Original patch by Ma Lin. - Revert bpo-26293 for zipfile breakage. See also bpo-29094.