capture_call_graph can show the current task and its await relationship during execution.
Python asyncio call graphs: inspect a live task without retaining frames
Operation contract
A task created inside TaskGroup captures its own graph. It reports that the graph refers to the running task and that an awaiting parent is recorded. The fixture prints only booleans, avoiding unstable frame addresses and line numbers in the displayed output.
Failure boundary
A graph is a momentary diagnostic, not a proof that the task will finish. Custom Future bridges need to register await relationships for a complete picture. Captured frames can retain local references; consume the result promptly and avoid storing it in a long-lived diagnostic cache. Task names and stacks can also expose sensitive data if logged raw.
Working program
import asyncio
async def inspect_receipt():
graph = asyncio.capture_call_graph(depth=0)
return (graph.future is asyncio.current_task(),
bool(graph.awaited_by))
async def main():
async with asyncio.TaskGroup() as group:
inspection = group.create_task(inspect_receipt())
current, awaited = inspection.result()
print("current_task", current)
print("awaited_by_parent", awaited)
asyncio.run(main())Output
current_task True
awaited_by_parent TrueCosts and limits
Walking a call graph takes time proportional to the captured stacks and await relationships. Keep diagnostics off hot request paths unless sampled and measured.
Common Mistakes
- A captured graph is not a completion guarantee.
- Do not retain frame-bearing graph objects indefinitely.
- Custom Future wrappers can hide relationships unless they cooperate.
