I am trying to call an async function from exec, I would expect it to work like:
def test():
print("test")
exec('def test2():\n print("test")\ntest2()')
test()
Output:
test
test
So a function defined in exec is able to call itself, however we can't do such things in asyncio as:
async def test():
print("test")
exec('async def test2():\n print("test")\nawait test2()')
We cant use await outside function as well as we cant call another loop from a running loop:
async def test():
print("test")
exec('async def test2():\n print("test")\nasyncio.run(test2())')
Is there any solution to this problem?
You can put current running loop as exec() global parameter:
import asyncio
async def test():
print("test")
loop = asyncio.get_running_loop()
exec('async def test2():\n print("test2")\nloop.create_task(test2())', {'loop': loop})
asyncio.run(test())
Prints:
test
test2
EDIT: To run asynchronously, you can return awaitable from the exec():
import asyncio
async def some_other_task():
await asyncio.sleep(1)
print('some_other_task')
async def test():
loop = asyncio.get_running_loop()
t = [None]
exec('async def test2():\n await asyncio.sleep(3);print("task in exec finished")\nt[0] = loop.create_task(test2())', {'asyncio': asyncio, 'loop': loop, 't': t})
await asyncio.gather(some_other_task(), t[0])
asyncio.run(test())
Prints:
some_other_task # <-- after 1 sec
task in exec finished # <-- after 3 sec
Not possible. You would need some kind of "asynchronous exec" capable of suspending its own execution, and Python's syntax would need to support await outside an asynchronous function definition. Without that, there's no way for exec to return control to the event loop when it needs to suspend.
Andrej Kesely's answer does not work. It does not actually run the coroutine. It only arranges for the coroutine to run later.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With