https://github.com/python/cpython/commit/35297007fd75bf417a36abbb21f6a8a00a402b8b
commit: 35297007fd75bf417a36abbb21f6a8a00a402b8b
branch: 3.15
author: Timofei Ivankov <[email protected]>
committer: hugovk <[email protected]>
date: 2026-09-11T21:04:35+03:00
summary:
[3.15] gh-157058: Fix missing awaited-by edge in wait_for(fut, 0) (GH-157059)
(#157322)
files:
A Misc/NEWS.d/next/Library/2026-09-07-12-24-11.gh-issue-157058.2SoQU7.rst
M Lib/asyncio/tasks.py
M Lib/test/test_asyncio/test_graph.py
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index e989498d6e8632b..d105f0c8efed7b7 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -541,6 +541,10 @@ async def _cancel_and_wait(fut):
cb = functools.partial(_release_waiter, waiter)
fut.add_done_callback(cb)
+ # gh-157058: awaiting the waiter leaves no edge on fut, add it here
+ cur_task = current_task()
+ futures.future_add_to_awaited_by(fut, cur_task)
+
try:
fut.cancel()
# We cannot wait on *fut* directly to make
@@ -548,6 +552,7 @@ async def _cancel_and_wait(fut):
await waiter
finally:
fut.remove_done_callback(cb)
+ futures.future_discard_from_awaited_by(fut, cur_task)
class _AsCompletedIterator:
diff --git a/Lib/test/test_asyncio/test_graph.py
b/Lib/test/test_asyncio/test_graph.py
index 50fa18e888fd22b..08e62f6e5bf19a2 100644
--- a/Lib/test/test_asyncio/test_graph.py
+++ b/Lib/test/test_asyncio/test_graph.py
@@ -146,6 +146,33 @@ async def main():
'async generator
CallStackTestBase.test_stack_async_gen.<locals>.gen()',
stack_for_gen_nested_call[1])
+ async def test_stack_wait_for_non_positive_timeout(self):
+ # gh-157058: wait_for(fut, 0) must still record the waiter
+ cleanup = asyncio.Future()
+
+ async def worker():
+ try:
+ await asyncio.Future()
+ finally:
+ await cleanup
+
+ async def probe(t):
+ await asyncio.wait_for(t, 0)
+
+ t = asyncio.ensure_future(worker())
+ p = asyncio.create_task(probe(t), name='probe')
+ for _ in range(5):
+ await asyncio.sleep(0)
+
+ stack = capture_test_stack(fut=t)
+
+ cleanup.set_result(None)
+ await asyncio.gather(p, t, return_exceptions=True)
+
+ self.assertEqual(stack[0][2], [
+ ['T<probe>', ['a _cancel_and_wait', 'a wait_for', 'a probe'], []],
+ ])
+
async def test_stack_gather(self):
stack_for_deep = None
diff --git
a/Misc/NEWS.d/next/Library/2026-09-07-12-24-11.gh-issue-157058.2SoQU7.rst
b/Misc/NEWS.d/next/Library/2026-09-07-12-24-11.gh-issue-157058.2SoQU7.rst
new file mode 100644
index 000000000000000..9122ae0919dcb11
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-09-07-12-24-11.gh-issue-157058.2SoQU7.rst
@@ -0,0 +1,2 @@
+:func:`asyncio.wait_for` with a non-positive timeout now records the waiter
+in the call graph.
_______________________________________________
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]