https://github.com/python/cpython/commit/306a35c71f1ceada3ea55479087d1c6a5cc8f15f
commit: 306a35c71f1ceada3ea55479087d1c6a5cc8f15f
branch: main
author: Raj Kripal Danday <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-07-26T14:38:51+05:30
summary:
gh-148736: Use ag_frame when walking async generators in asyncio.graph (#148737)
files:
A Misc/NEWS.d/next/Library/2026-04-18-12-00-00.gh-issue-148736.ag-frame.rst
M Lib/asyncio/graph.py
M Lib/test/test_asyncio/test_graph.py
diff --git a/Lib/asyncio/graph.py b/Lib/asyncio/graph.py
index 35f7fa62140bd4..7e85e08c4291a0 100644
--- a/Lib/asyncio/graph.py
+++ b/Lib/asyncio/graph.py
@@ -62,7 +62,7 @@ def _build_graph_for_future(
coro = coro.cr_await
elif hasattr(coro, 'ag_await'):
# A native async generator or duck-type compatible iterator
- st.append(FrameCallGraphEntry(coro.cr_frame))
+ st.append(FrameCallGraphEntry(coro.ag_frame))
coro = coro.ag_await
else:
break
diff --git a/Lib/test/test_asyncio/test_graph.py
b/Lib/test/test_asyncio/test_graph.py
index 3dde7535284b25..928b618fe5c55b 100644
--- a/Lib/test/test_asyncio/test_graph.py
+++ b/Lib/test/test_asyncio/test_graph.py
@@ -1,5 +1,6 @@
import asyncio
import io
+import sys
import unittest
from unittest import mock
@@ -147,6 +148,31 @@ async def main():
'async generator
CallStackTestBase.test_stack_async_gen.<locals>.gen()',
stack_for_gen_nested_call[1])
+ def test_ag_frame_used_for_async_generator(self):
+ # Regression test for gh-148736: the ag_await branch of
+ # _build_graph_for_future must read ag_frame, not cr_frame.
+ from asyncio.graph import _build_graph_for_future
+
+ sentinel_frame = sys._getframe()
+
+ class FakeAsyncGen:
+ ag_await = None
+ ag_frame = sentinel_frame
+
+ class FakeCoro:
+ cr_frame = sentinel_frame
+ cr_await = FakeAsyncGen()
+
+ loop = asyncio.new_event_loop()
+ try:
+ fut = loop.create_future()
+ fut.get_coro = lambda: FakeCoro()
+ result = _build_graph_for_future(fut)
+ finally:
+ loop.close()
+
+ self.assertEqual(len(result.call_stack), 2)
+
async def test_stack_gather(self):
stack_for_deep = None
diff --git
a/Misc/NEWS.d/next/Library/2026-04-18-12-00-00.gh-issue-148736.ag-frame.rst
b/Misc/NEWS.d/next/Library/2026-04-18-12-00-00.gh-issue-148736.ag-frame.rst
new file mode 100644
index 00000000000000..e9701dfaa6a48d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-04-18-12-00-00.gh-issue-148736.ag-frame.rst
@@ -0,0 +1,3 @@
+Fix a latent :exc:`AttributeError` in :mod:`asyncio` call-graph capture when
+walking an async generator's ``ag_await`` chain: the walker referenced
+``cr_frame`` instead of ``ag_frame``.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]