Python asyncio task cancel message not propagated

43 Views Asked by At

I am having a hard time understanding how asyncio.CancelledError is propagating. I have the following code:

import asyncio
import traceback


async def uselessTask():
    return await asyncio.sleep(10)


async def mainAsync():
    task = asyncio.create_task(uselessTask())
    asyncio.get_running_loop().call_later(1, lambda: task.cancel("CANCELLING USELESS TASK"))

    try:
        results = await task

    except asyncio.CancelledError as exc:
        print(f"Caught exception {type(exc).__name__}: {exc}")
        print(f"Task: {task}")
        traceback.print_exc()

    return

asyncio.run(mainAsync())

The execution of the above yields the following (both for python 3.9.6 and 3.10.7):

Caught exception CancelledError: 
Task: <Task cancelled name='Task-2' coro=<uselessTask() done, defined at C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py:5>>
Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 6, in uselessTask
    return await asyncio.sleep(10)
  File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\asyncio\tasks.py", line 605, in sleep
    return await future
asyncio.exceptions.CancelledError: CANCELLING USELESS TASK

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 14, in mainAsync
    results = await task
asyncio.exceptions.CancelledError

Process finished with exit code 0

however my expectation is that the exception caught during execution of results = await task is the same exact one that happened in the task and therefore present the same cancellation message "CANCELLING USELESS TASK".

However as you can see there is no cancellation message on the asyncio.CancelledError caused by consuming the task.

the other odd thing that I am not understanding is, if i break in the exception block and inspect the task variable, i see that the task is cancelled, however the _cancel_message is empty.

no cancellation message

I am not exactly understanding why the exceptions are bubbling that way or why the cancellation message is not seen other than in the task (for instance if i try:except: the uselessTask() function, the caught exception has the message). Also, the traceback message "During handling of the above exception, another exception occurred:" seems to indicate that no exception chaining happened as chaining yields "The above exception was the direct cause of the following exception:"

I am browsing the python documentation but i cannot seem to correlate what i am seeing to what is written.

EDIT:

Just to show better my expectation:

import asyncio
import traceback


async def uselessTask():
    try:
        await asyncio.sleep(10)
    except asyncio.CancelledError as exc:
        raise RuntimeError(*exc.args)

    return



async def mainAsync():
    task = asyncio.create_task(uselessTask())
    asyncio.get_running_loop().call_later(1, lambda: task.cancel("CANCELLING USELESS TASK"))

    try:
        results = await task

    except (asyncio.CancelledError, RuntimeError) as exc:
        print(f"Caught exception {type(exc).__name__}: {exc}")
        print(f"Task: {task}")
        traceback.print_exc()

    return

asyncio.run(mainAsync())

This code returns

Caught exception RuntimeError: CANCELLING USELESS TASK
Task: <Task finished name='Task-2' coro=<uselessTask() done, defined at C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py:5> exception=RuntimeError('CANCELLING USELESS TASK')>
Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 7, in uselessTask
    await asyncio.sleep(10)
  File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\asyncio\tasks.py", line 605, in sleep
    return await future
asyncio.exceptions.CancelledError: CANCELLING USELESS TASK

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 20, in mainAsync
    results = await task
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 9, in uselessTask
    raise RuntimeError(*exc.args)
RuntimeError: CANCELLING USELESS TASK

Process finished with exit code 0

This code on the other hand

import asyncio
import traceback


async def uselessTask():
    try:
        await asyncio.sleep(10)
    except asyncio.CancelledError as exc:
        raise asyncio.CancelledError(*exc.args)

    return



async def mainAsync():
    task = asyncio.create_task(uselessTask())
    asyncio.get_running_loop().call_later(1, lambda: task.cancel("CANCELLING USELESS TASK"))

    try:
        results = await task

    except (asyncio.CancelledError, RuntimeError) as exc:
        print(f"Caught exception {type(exc).__name__}: {exc}")
        print(f"Task: {task}")
        traceback.print_exc()

    return

asyncio.run(mainAsync())

Returns this:

Caught exception CancelledError: 
Task: <Task cancelled name='Task-2' coro=<uselessTask() done, defined at C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py:5>>
Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 7, in uselessTask
    await asyncio.sleep(10)
  File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\asyncio\tasks.py", line 605, in sleep
    return await future
asyncio.exceptions.CancelledError: CANCELLING USELESS TASK

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 9, in uselessTask
    raise asyncio.CancelledError(*exc.args)
asyncio.exceptions.CancelledError: CANCELLING USELESS TASK

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 20, in mainAsync
    results = await task
asyncio.exceptions.CancelledError

Process finished with exit code 0

as you can see, unwrapping the task result raises the asyncio.CancelledError but the message is now gone, while when raising any other exception, the unwrapping preserves the Exception arguments

0

There are 0 best solutions below