Title: Future.cancelled is not set to true immediately after calling Future.cancel
Type: behavior Stage: resolved
Components: asyncio Versions: Python 3.7
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Roland Netzsch, asvetlov, yselivanov
Priority: normal Keywords:

Created on 2019-06-08 11:07 by Roland Netzsch, last changed 2019-06-14 14:02 by asvetlov. This issue is now closed.

File name Uploaded Description Edit Roland Netzsch, 2019-06-08 11:07
Messages (5)
msg345029 - (view) Author: Roland Netzsch (Roland Netzsch) Date: 2019-06-08 11:07
The attached file produces the following output:

    wait is still running
    wait is not set to cancelled!
    Awaiting cancelled future produced a CancelledError.

A look a the documentation does not suggest a need to await the future in order to make sure the cancelled-flag is being set.
msg345030 - (view) Author: Roland Netzsch (Roland Netzsch) Date: 2019-06-08 11:15

[stuxcrystal@caprica ~]$ python3.7 --version
Python 3.7.3

Additional Notes:
Distribution: Fedora 30 (Workstation Edition)
Kernel: x86_64 Linux 5.0.9-301.fc30.x86_64
msg345036 - (view) Author: Andrew Svetlov (asvetlov) * (Python committer) Date: 2019-06-08 13:21
This is the expected behavior.

asyncio.ensure_future() returns not a future but a task for your case.
Task cancellation requires at least one context switch to finish the task.

I suggest replacing `asyncio.ensure_future()` with `asyncio.create_task()` to avoid confusion.
msg345038 - (view) Author: Roland Netzsch (Roland Netzsch) Date: 2019-06-08 14:03
So there is no way to reliably find out whether a task has been cancelled by calling Task.cancelled()?
msg345048 - (view) Author: Andrew Svetlov (asvetlov) * (Python committer) Date: 2019-06-08 15:23
I don't follow what reliability guarantee are you requesting.

A cite from task.cancel() docstring:

> Request that this task cancel itself.

        This arranges for a CancelledError to be thrown into the
        wrapped coroutine on the next cycle through the event loop.
        The coroutine then has a chance to clean up or even deny
        the request using try/except/finally.

        Unlike Future.cancel, this does not guarantee that the
        task will be cancelled: the exception might be caught and
        acted upon, delaying cancellation of the task or preventing
        cancellation completely.  The task may also return a value or
        raise a different exception.

        Immediately after this method is called, Task.cancelled() will
        not return True (unless the task was already cancelled).  A
        task will be marked as cancelled when the wrapped coroutine
        terminates with a CancelledError exception (even if cancel()
        was not called).

task.cancelled() returns True for canceled and finished tasks, but task.cancel() is a request for cancellation. The requested task needs some time to gracefully finish itself.
Date User Action Args
2019-06-14 14:02:14asvetlovsetstatus: open -> closed
stage: resolved
2019-06-08 19:32:39Roland Netzschsetresolution: not a bug
2019-06-08 15:23:55asvetlovsetmessages: + msg345048
2019-06-08 14:03:55Roland Netzschsetmessages: + msg345038
2019-06-08 13:21:37asvetlovsetmessages: + msg345036
2019-06-08 11:15:16Roland Netzschsetmessages: + msg345030
2019-06-08 11:07:20Roland Netzschcreate