diff options
author | INADA Naoki <methane@users.noreply.github.com> | 2017-05-11 12:18:38 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-11 12:18:38 (GMT) |
commit | 991adca012f5e106c2d4040ce619c696ba6f9c46 (patch) | |
tree | 90fa267454273f2e779ceffbeeae2ff84d5f01ca /Lib | |
parent | c4750959acbfc3057f12aaec832483ba30898d1c (diff) | |
download | cpython-991adca012f5e106c2d4040ce619c696ba6f9c46.zip cpython-991adca012f5e106c2d4040ce619c696ba6f9c46.tar.gz cpython-991adca012f5e106c2d4040ce619c696ba6f9c46.tar.bz2 |
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
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/asyncio/tasks.py | 7 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_tasks.py | 18 |
2 files changed, 24 insertions, 1 deletions
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 4fbcf3e..e453300 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -176,7 +176,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 754a675..988b288 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -587,6 +587,24 @@ class BaseTaskTests: 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 = self.new_task(loop, task()) + 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(): |