mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			145 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			145 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| .. currentmodule:: asyncio
 | |
| 
 | |
| 
 | |
| .. _asyncio-graph:
 | |
| 
 | |
| ========================
 | |
| Call Graph Introspection
 | |
| ========================
 | |
| 
 | |
| **Source code:** :source:`Lib/asyncio/graph.py`
 | |
| 
 | |
| -------------------------------------
 | |
| 
 | |
| asyncio has powerful runtime call graph introspection utilities
 | |
| to trace the entire call graph of a running *coroutine* or *task*, or
 | |
| a suspended *future*.  These utilities and the underlying machinery
 | |
| can be used from within a Python program or by external profilers
 | |
| and debuggers.
 | |
| 
 | |
| .. versionadded:: 3.14
 | |
| 
 | |
| 
 | |
| .. function:: print_call_graph(future=None, /, *, file=None, depth=1, limit=None)
 | |
| 
 | |
|    Print the async call graph for the current task or the provided
 | |
|    :class:`Task` or :class:`Future`.
 | |
| 
 | |
|    This function prints entries starting from the top frame and going
 | |
|    down towards the invocation point.
 | |
| 
 | |
|    The function receives an optional *future* argument.
 | |
|    If not passed, the current running task will be used.
 | |
| 
 | |
|    If the function is called on *the current task*, the optional
 | |
|    keyword-only *depth* argument can be used to skip the specified
 | |
|    number of frames from top of the stack.
 | |
| 
 | |
|    If the optional keyword-only *limit* argument is provided, each call stack
 | |
|    in the resulting graph is truncated to include at most ``abs(limit)``
 | |
|    entries. If *limit* is positive, the entries left are the closest to
 | |
|    the invocation point. If *limit* is negative, the topmost entries are
 | |
|    left. If *limit* is omitted or ``None``, all entries are present.
 | |
|    If *limit* is ``0``, the call stack is not printed at all, only
 | |
|    "awaited by" information is printed.
 | |
| 
 | |
|    If *file* is omitted or ``None``, the function will print
 | |
|    to :data:`sys.stdout`.
 | |
| 
 | |
|    **Example:**
 | |
| 
 | |
|    The following Python code:
 | |
| 
 | |
|    .. code-block:: python
 | |
| 
 | |
|       import asyncio
 | |
| 
 | |
|       async def test():
 | |
|           asyncio.print_call_graph()
 | |
| 
 | |
|       async def main():
 | |
|           async with asyncio.TaskGroup() as g:
 | |
|               g.create_task(test(), name='test')
 | |
| 
 | |
|       asyncio.run(main())
 | |
| 
 | |
|    will print::
 | |
| 
 | |
|       * Task(name='test', id=0x1039f0fe0)
 | |
|       + Call stack:
 | |
|       |   File 't2.py', line 4, in async test()
 | |
|       + Awaited by:
 | |
|          * Task(name='Task-1', id=0x103a5e060)
 | |
|             + Call stack:
 | |
|             |   File 'taskgroups.py', line 107, in async TaskGroup.__aexit__()
 | |
|             |   File 't2.py', line 7, in async main()
 | |
| 
 | |
| .. function:: format_call_graph(future=None, /, *, depth=1, limit=None)
 | |
| 
 | |
|    Like :func:`print_call_graph`, but returns a string.
 | |
|    If *future* is ``None`` and there's no current task,
 | |
|    the function returns an empty string.
 | |
| 
 | |
| 
 | |
| .. function:: capture_call_graph(future=None, /, *, depth=1, limit=None)
 | |
| 
 | |
|    Capture the async call graph for the current task or the provided
 | |
|    :class:`Task` or :class:`Future`.
 | |
| 
 | |
|    The function receives an optional *future* argument.
 | |
|    If not passed, the current running task will be used. If there's no
 | |
|    current task, the function returns ``None``.
 | |
| 
 | |
|    If the function is called on *the current task*, the optional
 | |
|    keyword-only *depth* argument can be used to skip the specified
 | |
|    number of frames from top of the stack.
 | |
| 
 | |
|    Returns a ``FutureCallGraph`` data class object:
 | |
| 
 | |
|    * ``FutureCallGraph(future, call_stack, awaited_by)``
 | |
| 
 | |
|       Where *future* is a reference to a :class:`Future` or
 | |
|       a :class:`Task` (or their subclasses.)
 | |
| 
 | |
|       ``call_stack`` is a tuple of ``FrameCallGraphEntry`` objects.
 | |
| 
 | |
|       ``awaited_by`` is a tuple of ``FutureCallGraph`` objects.
 | |
| 
 | |
|    * ``FrameCallGraphEntry(frame)``
 | |
| 
 | |
|       Where *frame* is a frame object of a regular Python function
 | |
|       in the call stack.
 | |
| 
 | |
| 
 | |
| Low level utility functions
 | |
| ===========================
 | |
| 
 | |
| To introspect an async call graph asyncio requires cooperation from
 | |
| control flow structures, such as :func:`shield` or :class:`TaskGroup`.
 | |
| Any time an intermediate :class:`Future` object with low-level APIs like
 | |
| :meth:`Future.add_done_callback() <asyncio.Future.add_done_callback>` is
 | |
| involved, the following two functions should be used to inform asyncio
 | |
| about how exactly such intermediate future objects are connected with
 | |
| the tasks they wrap or control.
 | |
| 
 | |
| 
 | |
| .. function:: future_add_to_awaited_by(future, waiter, /)
 | |
| 
 | |
|    Record that *future* is awaited on by *waiter*.
 | |
| 
 | |
|    Both *future* and *waiter* must be instances of
 | |
|    :class:`Future` or :class:`Task` or their subclasses,
 | |
|    otherwise the call would have no effect.
 | |
| 
 | |
|    A call to ``future_add_to_awaited_by()`` must be followed by an
 | |
|    eventual call to the :func:`future_discard_from_awaited_by` function
 | |
|    with the same arguments.
 | |
| 
 | |
| 
 | |
| .. function:: future_discard_from_awaited_by(future, waiter, /)
 | |
| 
 | |
|    Record that *future* is no longer awaited on by *waiter*.
 | |
| 
 | |
|    Both *future* and *waiter* must be instances of
 | |
|    :class:`Future` or :class:`Task` or their subclasses, otherwise
 | |
|    the call would have no effect.
 | 
