Created
May 23, 2020 12:56
-
-
Save timmwagener/dfed038dc2081c8b5a770e175ba3756b to your computer and use it in GitHub Desktop.
Test gather cancellation and resulting state.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
"""Test gather cancellation and resulting state. | |
SeeAlso: | |
https://stackoverflow.com/questions/61942306/asyncio-gather-task-cancelled-is-false-after-task-cancel | |
Here's my take on what's happening: | |
* future_gather.cancel() cancels task_child | |
* await future_gather will cause task_child to run and raise CancelledError | |
* task_child's done callback for future_gather is invoked | |
* _done_callback(task_child) calls future_gather.set_exception(CancelledError()) which sets: | |
* future_gather._exception = CancelledError() | |
* future_gather._state = _FINISHED | |
* await calls future_gather.result() which raises self._exception if set | |
Therefore the end result is a future whose: | |
* .cancel() has been called | |
* has explicitly raised a CancelledError to clients | |
* returns a CancelledError for .exception() | |
* returns False for .cancelled() | |
* has a _state of FINISHED (not CANCELLED) | |
""" | |
import logging | |
from asyncio import CancelledError | |
from asyncio import ensure_future | |
from asyncio import gather | |
from asyncio import run | |
from asyncio import sleep | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
async def main(): | |
"""Cancel a gather() future and child and return it.""" | |
task_child = ensure_future(sleep(1.0)) | |
future_gather = gather(task_child) | |
future_gather.cancel() | |
try: | |
await future_gather | |
except CancelledError: | |
pass | |
return future_gather, task_child | |
# run | |
future_gather, task_child = run(main()) | |
# log gather state | |
logger.info(f"gather:") | |
logger.info(f"cancelled: {future_gather.cancelled()}") | |
logger.info(f"done: {future_gather.done()}") | |
logger.info(f"exception: {future_gather.exception()!r}") | |
logger.info(f"state: {future_gather._state}") | |
logger.info(f"") | |
# log child state | |
logger.info(f"child:") | |
logger.info(f"cancelled: {task_child.cancelled()}") | |
logger.info(f"done: {task_child.done()}") | |
# logger.info(f"exception: {task_child.exception()}") Raises because _state is CANCELLED | |
logger.info(f"state: {task_child._state}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment