Skip to content

gh-135371: Fix asyncio introspection output to include internal coroutine chains #135436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 14, 2025

Conversation

pablogsal
Copy link
Member

@pablogsal pablogsal commented Jun 12, 2025

…acks

This commit refactors the C module to provide richer debugging information
by introducing structured data types and exposing internal coroutine call
stacks. The improvement transforms the debugging output from showing only
external task dependencies to revealing the complete execution context.

The key enhancement is the ability to display both the internal coroutine
call stack (what the task is doing internally) and the external awaiter
chain (what the task is waiting for). This dual perspective makes it much
easier to understand complex async execution patterns.

Before this change, the debugging output only showed file paths without
function names or internal call stacks. With this improvement, developers
can now see the complete picture: "foo2 -> sleep" shows the task is in
a sleep call within the foo2 function, while the awaiter chain shows the
external dependency structure.

The implementation replaces raw tuples with structured sequences:
- FrameInfo: Function name, filename, and line number
- CoroInfo: Call stack and associated task name
- TaskInfo: Task ID, name, coroutine stack, and awaiter relationships
- ThreadInfo: Thread ID and frame information
- AwaitedInfo: Thread ID and list of awaited tasks

This structured approach eliminates magic indices and provides better
type safety and introspection capabilities.
This commit updates the asyncio debugging tools to work with the enhanced
structured data from the remote debugging module. The tools now process
and display both internal coroutine stacks and external awaiter chains,
providing much more comprehensive debugging information.

The key improvements include:

1. Enhanced table display: Now shows both "coroutine stack" and "awaiter
   chain" columns, clearly separating what a task is doing internally vs
   what it's waiting for externally.

2. Improved tree rendering: Displays complete coroutine call stacks for
   leaf tasks, making it easier to understand the actual execution state
   of suspended coroutines.

3. Better cycle detection: Optimized DFS algorithm for detecting await
   cycles in the task dependency graph.

4. Structured data handling: Updated to work with the new FrameInfo,
   CoroInfo, TaskInfo, and AwaitedInfo structured types instead of raw
   tuples.

The enhanced output transforms debugging from showing only file paths to
revealing function names and complete call stacks, making it much easier
to understand complex async execution patterns and diagnose issues in
production asyncio applications.
This commit updates the test suite to work with the new structured data
types introduced in the remote debugging module and asyncio tools. The
tests now use proper FrameInfo, CoroInfo, TaskInfo, and AwaitedInfo
structures instead of raw tuples.

The test updates ensure that the enhanced debugging capabilities are
properly validated, including:

1. Structured data type handling in test mock data
2. Verification of coroutine stack extraction and formatting
3. Testing of both internal coroutine stacks and external awaiter chains
4. Validation of the improved table and tree output formats

These changes maintain comprehensive test coverage while adapting to the
more sophisticated data structures that enable better async debugging
output. The tests verify that the debugging tools correctly process and
display the enhanced coroutine execution information, ensuring the new
features work reliably in production environments.
This commit updates the What's New documentation to showcase the improved
async debugging capabilities introduced in the remote debugging module
and asyncio tools. The documentation now demonstrates the enhanced output
format that provides much more detailed execution information.

The key documentation updates include:

1. Updated example output showing both "coroutine stack" and "awaiter
   chain" columns in the table format, clearly distinguishing between
   internal task execution state and external dependencies.

2. Enhanced tree output examples that include function names and complete
   file paths with line numbers, making the debugging information much
   more actionable for developers.

3. Addition of cycle detection error example showing how the tools handle
   problematic await patterns that could indicate programming issues.

The updated examples demonstrate how the enhanced debugging output
transforms from showing basic file paths to revealing detailed function
call stacks and execution context. This improvement makes it significantly
easier for developers to understand complex async execution patterns and
debug issues in production asyncio applications, especially when dealing
with nested coroutines and complex task hierarchies.
@pablogsal pablogsal merged commit 028309f into python:main Jun 14, 2025
39 checks passed
@pablogsal pablogsal deleted the better_coros-2 branch June 14, 2025 12:48
@miss-islington-app
Copy link

Thanks @pablogsal for the PR 🌮🎉.. I'm working now to backport this PR to: 3.14.
🐍🍒⛏🤖 I'm not a witch! I'm not a witch!

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jun 14, 2025
… coroutine chains (pythonGH-135436)

(cherry picked from commit 028309f)

Co-authored-by: Pablo Galindo Salgado <[email protected]>
@bedevere-app
Copy link

bedevere-app bot commented Jun 14, 2025

GH-135509 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.14 bugs and security fixes label Jun 14, 2025
@bedevere-bot
Copy link

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot ARM64 Raspbian 3.x (tier-3) has failed when building commit 028309f.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/1678/builds/294) and take a look at the build logs.
  4. Check if the failure is related to this commit (028309f) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/1678/builds/294

Failed tests:

  • test_external_inspection

Failed subtests:

  • test_async_global_awaited_by - test.test_external_inspection.TestGetStackTrace.test_async_global_awaited_by

Summary of the results of the build (if available):

==

Click to see traceback logs
Traceback (most recent call last):
  File "/home/stan/buildarea/3.x.stan-raspbian.nondebug/build/Lib/test/test_external_inspection.py", line 640, in test_async_global_awaited_by
    all_awaited_by = get_all_awaited_by(p.pid)
  File "/home/stan/buildarea/3.x.stan-raspbian.nondebug/build/Lib/test/test_external_inspection.py", line 56, in get_all_awaited_by
    return unwinder.get_all_awaited_by()
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
RuntimeError: Failed to append awaited_by for thread in get_all_awaited_by

@bedevere-bot
Copy link

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 CentOS9 NoGIL Refleaks 3.x (tier-1) has failed when building commit 028309f.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/1610/builds/1577) and take a look at the build logs.
  4. Check if the failure is related to this commit (028309f) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/1610/builds/1577

Failed tests:

  • test_free_threading

Summary of the results of the build (if available):

==

Click to see traceback logs
remote: Enumerating objects: 19, done.        
remote: Counting objects:   5% (1/18)        
remote: Counting objects:  11% (2/18)        
remote: Counting objects:  16% (3/18)        
remote: Counting objects:  22% (4/18)        
remote: Counting objects:  27% (5/18)        
remote: Counting objects:  33% (6/18)        
remote: Counting objects:  38% (7/18)        
remote: Counting objects:  44% (8/18)        
remote: Counting objects:  50% (9/18)        
remote: Counting objects:  55% (10/18)        
remote: Counting objects:  61% (11/18)        
remote: Counting objects:  66% (12/18)        
remote: Counting objects:  72% (13/18)        
remote: Counting objects:  77% (14/18)        
remote: Counting objects:  83% (15/18)        
remote: Counting objects:  88% (16/18)        
remote: Counting objects:  94% (17/18)        
remote: Counting objects: 100% (18/18)        
remote: Counting objects: 100% (18/18), done.        
remote: Compressing objects:   7% (1/14)        
remote: Compressing objects:  14% (2/14)        
remote: Compressing objects:  21% (3/14)        
remote: Compressing objects:  28% (4/14)        
remote: Compressing objects:  35% (5/14)        
remote: Compressing objects:  42% (6/14)        
remote: Compressing objects:  50% (7/14)        
remote: Compressing objects:  57% (8/14)        
remote: Compressing objects:  64% (9/14)        
remote: Compressing objects:  71% (10/14)        
remote: Compressing objects:  78% (11/14)        
remote: Compressing objects:  85% (12/14)        
remote: Compressing objects:  92% (13/14)        
remote: Compressing objects: 100% (14/14)        
remote: Compressing objects: 100% (14/14), done.        
remote: Total 19 (delta 4), reused 4 (delta 4), pack-reused 1 (from 1)        
From https://github.com/python/cpython
 * branch                    main       -> FETCH_HEAD
Note: switching to '028309fb47869b665f55d10e9eabf7952bf7dbd3'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 028309fb478 gh-135371: Fix asyncio introspection output to include internal coroutine chains (#135436)
Switched to and reset branch 'main'

configure: WARNING: no system libmpdecimal found; falling back to bundled libmpdecimal (deprecated and scheduled for removal in Python 3.15)

make: *** [Makefile:2454: buildbottest] Error 2

@pablogsal
Copy link
Member Author

The raspbian buildbot looks legitimate will take a look soon.

pablogsal added a commit that referenced this pull request Jun 15, 2025
…l coroutine chains (GH-135436) (#135509)

gh-135371: Fix asyncio introspection output to include internal coroutine chains (GH-135436)
(cherry picked from commit 028309f)

Co-authored-by: Pablo Galindo Salgado <[email protected]>
shuimu5418 pushed a commit to shuimu5418/cpython001 that referenced this pull request Jun 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants