← index #6174Issue #5881
Related · high · value 3.041
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 · ISSUE

extmod/uasyncio Discrepancy between behaviour and docs

closedby peterhinchopened 2020-04-08updated 2020-04-08

The doc for the class Task states:

Task.cancel()

Cancel the task by injecting a CancelledError into it. The task may or may not ignore this exception.

The following script produces identical results in CPython 3.8 and MicroPython, with no exception occurring in bar(). The script runs correctly apart from this.

Is there in fact a way to detect cancellation within a task, or are the docs wrong?

try:
    import uasyncio as asyncio
except ImportError:
    import asyncio

async def bar():
    try:
        while True:
            print('Bar running')
            await asyncio.sleep(1)
    except Exception as e:
        print('bar stopped.', e)  # Never happens (CPython or mp)

async def main():
    t = asyncio.create_task(bar())
    await asyncio.sleep(2)
    t.cancel()
    await asyncio.sleep(1)

asyncio.run(main())

Detecting cancellation or timeouts within a task is actually very useful e.g. for cleanup, if there is a way to achieve it.

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