← index #6174PR #8929
Off-topic · high · value 1.143
QUERY · ISSUE

uasyncio: Code throws exception under CPython

openby peterhinchopened 2020-06-19updated 2020-06-21
extmod

MicroPython allows a task to be created before issuing .run() but CPython throws an exception.

try:
    import uasyncio as asyncio
except ImportError:
    import asyncio

async def foo():
    await asyncio.sleep(3)

async def bar():
    await foo_task

foo_task = asyncio.create_task(foo())  # Naughty code here...
asyncio.run(bar())

Outcome under CPython 3.8.0:

adminpete@debian8:/mnt/qnap2/temp$ python3 -m rats_x
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/runpy.py", line 192, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/local/lib/python3.8/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/mnt/qnap2/temp/rats_x.py", line 12, in <module>
    foo_task = asyncio.create_task(foo())
  File "/usr/local/lib/python3.8/asyncio/tasks.py", line 381, in create_task
    loop = events.get_running_loop()
RuntimeError: no running event loop
sys:1: RuntimeWarning: coroutine 'foo' was never awaited

My view is that this doesn't matter, but I thought it worth reporting.

CANDIDATE · PULL REQUEST

extmod/uasyncio/task.py: Fix crash when non-awaited task is awaited.

closedby jimmoopened 2022-07-19updated 2024-02-25
extmod

A task that has been sent to the loop's exception handler due to being re-scheduled twice will then subsequently cause a raise None if it is subsequently awaited. In the C version of task.py, this causes a segfault.

async def task():
    raise Exception("task")

t = asyncio.create_task(task())
await asyncio.sleep(0)
await asyncio.sleep(0)  # <-- loop exception handler called here
await t  # <-- this line crashes

This PR makes the await succeed (via raising StopIteration instead).

I'm not sure this is the right fix though... it seems wrong to make the await succeed. The other option that I can think of are:

  • Improve the logic for detecting the "un-awaited" task. Without reference counting this seems impossible.
  • Make the task retain its exception, and even after it has been delivered to the loop's exception handler, still have await raise the original exception.
  • Make the await raise CancelledError.

I think the third option (CancelledError) might be the most pragmatic alternative?

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied