https://github.com/python/cpython/commit/3945eaf2fcd9cbc3f3061275bd29751c8b2e7d3b
commit: 3945eaf2fcd9cbc3f3061275bd29751c8b2e7d3b
branch: main
author: Abhinav <[email protected]>
committer: asvetlov <[email protected]>
date: 2026-11-03T00:08:42+01:00
summary:

gh-158097: Make test_staggered_race_with_eager_tasks deterministic (#158469)

* gh-158097: Make test_staggered_race_with_eager_tasks deterministic

staggered_race() awaits the coroutines it is given inline, so the
"await asyncio.sleep(0)" in the test's fail() helper suspended the
run_one_coro() task running it and left a scheduled resumption behind.
If the asyncio.sleep(1) winner (started 0.25s late by the stagger delay)
completes before that resumption runs, the winner's cancel() sets
_must_cancel and the resumption throws CancelledError into fail(), so
excs[2] reports a CancelledError instead of a ValueError.

Pending timers are only moved onto the ready queue at the top of
BaseEventLoop._run_once() and are appended after the handles already
queued, so the t=0.50s stagger timer and the t=1.25s sleep(1) timer run
in due-time order.  When both are due in the same _run_once() - which is
what a busy CI machine causes - the stagger timer starts fail(), which
immediately suspends again, and the very next handle is the winner.

Raise straight away instead, so the ValueError is stored in excs[2] in
the same step that starts the coroutine and there is no longer a
scheduled resumption for a cancellation to overtake.  The outcome no
longer depends on the event loop getting another iteration.

* Update Lib/test/test_asyncio/test_eager_task_factory.py

* Delete Misc/NEWS.d/next/Tests/2026-09-30-00-00-00.gh-issue-158097.pcB3mO.rst

---------

Co-authored-by: abhinav-phi <[email protected]>
Co-authored-by: Andrew Svetlov <[email protected]>

files:
M Lib/test/test_asyncio/test_eager_task_factory.py

diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py 
b/Lib/test/test_asyncio/test_eager_task_factory.py
index 594a48baa32e52..73496de81a58ef 100644
--- a/Lib/test/test_asyncio/test_eager_task_factory.py
+++ b/Lib/test/test_asyncio/test_eager_task_factory.py
@@ -217,7 +217,9 @@ def test_staggered_race_with_eager_tasks(self):
         # See https://github.com/python/cpython/issues/124309
 
         async def fail():
-            await asyncio.sleep(0)
+            # Raise without suspending: staggered_race() cancels unfinished
+            # coroutines once another one wins, so yielding first could turn
+            # this into a CancelledError when the event loop is busy.
             raise ValueError("no good")
 
         async def blocked():

_______________________________________________
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]

Reply via email to