python-trio / trio-asyncio

a re-implementation of the asyncio mainloop on top of Trio
Other
188 stars 38 forks source link

AttributeError: 'NoneType' object has no attribute 'run_aio_coroutine' #110

Closed mozesa closed 3 years ago

mozesa commented 3 years ago

Hello!

The below code throws AttributeError: 'NoneType' object has no attribute 'run_aio_coroutine'. I could boil down to that the cause of it is trio.lowlevel.spawn_system_task(async_main). When I use a nursery, it does its job fine.

Now the question is that it is bug or feature? 😄

import trio
import trio_asyncio
from asyncua import Client
from trio_asyncio import aio_as_trio

async def async_main():
    async with aio_as_trio(Client("opc.tcp://192.168.0.10:4840/")) as client:
        print("OK")

async def test_spawn_system_task():
    # async with trio.open_nursery() as nursery:
    #     nursery.start_soon(async_main)

    trio.lowlevel.spawn_system_task(async_main)
    await trio.sleep_forever()

if __name__ == "__main__":
    trio_asyncio.run(test_spawn_system_task)

image

Traceback

Traceback (most recent call last):
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\trio\_core\_run.py", line 2185, in unrolled_run
    runner.task_exited(task, final_outcome)
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\trio\_core\_run.py", line 1511, in task_exited
    outcome.unwrap()
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\outcome\_impl.py", line 138, in unwrap
    raise captured_error
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\trio\_core\_run.py", line 1605, in init
    self.system_nursery.cancel_scope.cancel()
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\trio\_core\_run.py", line 815, in __aexit__
    raise combined_error_from_nursery
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\acps_asm_v316_v2\test_opcua_client.py", line 8, in async_main
    async with aio_as_trio(Client("opc.tcp://192.168.0.10:4840/")) as client:
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\trio_asyncio\_adapter.py", line 73, in __aenter__
    return self.loop.run_aio_coroutine(f)
AttributeError: 'NoneType' object has no attribute 'run_aio_coroutine'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\acps_asm_v316_v2\test_opcua_client.py", line 21, in <module>
    trio_asyncio.run(test_spawn_system_task)
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\trio_asyncio\_loop.py", line 446, in run
    return trio.run(_run_task, proc, args)
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\trio\_core\_run.py", line 1923, in run
    timeout = gen.send(next_send)
  File "C:\Users\mozesa\PycharmProjects\acps-asm-v316-v2\.venv\lib\site-packages\trio\_core\_run.py", line 2230, in unrolled_run
    raise TrioInternalError("internal error in Trio - please file a bug!") from exc
trio.TrioInternalError: internal error in Trio - please file a bug!
sys:1: RuntimeWarning: coroutine 'Client.__aenter__' was never awaited

Process finished with exit code 1
AndreasHeine commented 3 years ago

looks like a missing await statement on asyncua client creation!

async with aio_as_trio(Client("opc.tcp://192.168.0.10:4840/")) as client:

not sure what this does aio_as_trio()

in asyncio it would look like this:

client = Client("opc.tcp://192.168.0.10:4840/")
async with client: #<--- __aenter__ is called here
        print("ok")
        await asyncio.sleep(1) #mabe trio has something similar !?
mozesa commented 3 years ago

I don't think so, it gives me the same error. The problem is what I would like to do is devil. 😈

aio_as_trio() helps me to be able to call asyncio corotunies within trio loop.

import trio
import trio_asyncio
from asyncua import Client
from trio_asyncio import aio_as_trio

async def async_main():
    client = Client("opc.tcp://192.168.0.10:4840/")
    async with aio_as_trio(client):
        print("OK")

async def test_spawn_system_task():
    # async with trio.open_nursery() as nursery:
    #     nursery.start_soon(async_main)

    trio.lowlevel.spawn_system_task(async_main)
    await trio.sleep_forever()

if __name__ == "__main__":
    trio_asyncio.run(test_spawn_system_task)
AndreasHeine commented 3 years ago

it gives me the same error.

off cource its the same error if you never await...

there are not much rules in life instead of the compiler/interpreter is always right!

parity3 commented 3 years ago

If it helps, I had this this same error message happen because I was trying to call an asyncio lib (triopg) from a thread pool (thread spawed from to_thread.run_sync).. Something to do with ContextVar or ThreadLocal not properly keeping the asyncio loop instance around I suppose. I worked around it by using a memory channel and never calling trio_asyncio methods directly from threads.

smurfix commented 3 years ago

Calling from threads doesn't work because the called code doesn't inherit the context cross-thread. Fixing that is somewhere on Trio's TODO list; trio-asyncio isn't the only package bitten by this.

mozesa commented 3 years ago

@oremanj a system task is “outside” the trio-asyncio loop and thus can’t access it