Is it possible to await
arbitrary calls to an async
function when inside a Python debugger?
Say I have the following code in some main.py
file:
import asyncio
async def bar(x):
return x + 1
async def foo():
import ipdb; ipdb.set_trace()
asyncio.run(foo())
Now I want to test calling bar()
with some argument inside the debugger to test the results. The following happens:
$ python3 main.py
> /Users/user/test/main.py(8)foo()
7 import ipdb; ipdb.set_trace()
----> 8 return None
9
ipdb> bar(1)
<coroutine object bar at 0x10404ae60>
main.py:1: RuntimeWarning: coroutine 'bar' was never awaited
import asyncio
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
ipdb> await bar(1)
*** SyntaxError: 'await' outside function
Of course, I can get around this by having x = await bar(1)
above my ipdb.set_trace()
, and then inspecting the results, but then I can't try calling my functions in real time while the debugger is active.
The await operator is used to wait for a Promise and get its fulfillment value. It can only be used inside an async function or a JavaScript module.
Python's asyncio package (introduced in Python 3.4) and its two keywords, async and await , serve different purposes but come together to help you declare, build, execute, and manage asynchronous code.
The await keyword can be put in front of any async coroutine-based function to pause your code on that line until the coroutine fulfills. Then, return the resulting value. In simpler words, you can think of the await keyword as the place where it is safe for one coroutine to move to another coroutine.
To run an async function (coroutine) you have to call it using an Event Loop. Event Loops: You can think of Event Loop as functions to run asynchronous tasks and callbacks, perform network IO operations, and run subprocesses. Example 1: Event Loop example to run async Function to run a single async function: Python3.
Seems like there's starting to be more support for this feature since Python 3.8. In particular, look at this issue bpo-37028
If you're still on Python 3.7, maybe aiomonitor could have something that supports this feature to a certain extent.
Here a modified version of what I posted at https://stackoverflow.com/a/67847257/893857 since it also solves this problem.
I found a solution using nest_asyncio. If one has the following async example script:
import asyncio
import nest_asyncio
async def bar(x):
return x + 1
async def foo():
import ipdb; ipdb.set_trace()
if __name__=="__main__":
loop = asyncio.get_event_loop()
nest_asyncio.apply(loop)
loop.run_until_complete(foo())
One can then do:
8 async def foo():
----> 9 import ipdb; ipdb.set_trace()
10
ipdb> loop = asyncio.get_event_loop()
ipdb> loop.run_until_complete(bar(1))
2
Admittedly it is a bit more tedious then await bar(1)
but it gets the job done. Hopefully a more elegant solution will come up in the future.
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