Python asyncio supports meaningful stack traces through async functions just fine.
import asyncio
async def baz():
await asyncio.sleep(.1)
raise RuntimeError()
async def bar():
await asyncio.sleep(.1)
await baz()
async def foo():
await asyncio.sleep(.1)
await bar()
async def main():
await asyncio.sleep(.1)
await foo()
if __name__ == "__main__":
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
main_task = loop.create_task(main())
try:
loop.run_until_complete(main_task)
except KeyboardInterrupt:
main_task.cancel()
loop.run_until_complete(asyncio.wait([main_task]))
pass
And then run:
$ python3 test_stacktrace.py
Traceback (most recent call last):
File "/home/user/tmp/test_stacktrace.py", line 24, in <module>
loop.run_until_complete(main_task)
File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "/home/user/tmp/test_stacktrace.py", line 17, in main
await foo()
File "/home/user/tmp/test_stacktrace.py", line 13, in foo
await bar()
File "/home/user/tmp/test_stacktrace.py", line 9, in bar
await baz()
File "/home/user/tmp/test_stacktrace.py", line 5, in baz
raise RuntimeError()
RuntimeError