Skip to content

asyncio.Task.cancel documentation is inaccurate #98275

Closed as not planned
Closed as not planned
@fancidev

Description

@fancidev

Problem

The documentation on asyncio.Task.cancel says

This arranges for a CancelledError exception to be thrown into the wrapped coroutine on the next cycle of the event loop.

The coroutine then has a chance to clean up or even deny the request by suppressing the exception with a try … … except CancelledError … finally block. Therefore, unlike Future.cancel(), Task.cancel() does not guarantee that the Task will be cancelled, although suppressing cancellation completely is not common and is actively discouraged.

These lines appear to suggest that a CancelledError will always be raised into the coroutine, which is not true -- if cancel() is called before the Task starts running, the task is guaranteed to be cancelled -- the coroutine is not given a chance to run at all and no exception is thrown into it.

Example

The following program prints nothing on stdout and exits with code 1.

import asyncio

async def test():
    try:
        print("test() is called!")
        await asyncio.sleep(1)
    except asyncio.CancelledError:
        print("test() is cancelled!")

async def main():
    task = asyncio.create_task(test())
    task.cancel()
    await task

asyncio.run(main())

Suggestion

Clarify that cancelling a task that has not started is always "effective" and will not cause an exception to be thrown into the coroutine.

Specifically, the quoted paragraphs might be amended as follows (key changes in bold):

If the Task has not started, it will be done with CancelledError and will not be started.

If the Task has started, a CancelledError exception will be thrown into the wrapped coroutine on the next cycle of the event loop. The coroutine then has a chance to clean up or even deny the request by suppressing the exception with a try … … except CancelledError … finally block. Therefore, unlike Future.cancel(), Task.cancel() does not guarantee that a started Task will be cancelled, although suppressing cancellation completely is not common and is actively discouraged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions