https://github.com/python/cpython/commit/6b142ab9a0007d37c68c74f81e2c8638330003e2
commit: 6b142ab9a0007d37c68c74f81e2c8638330003e2
branch: main
author: Pablo Galindo Salgado <[email protected]>
committer: encukou <[email protected]>
date: 2026-06-17T15:17:16+02:00
summary:

gh-150966: Fix live profiling error tests (GH-151020)

files:
A Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst
M Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py

diff --git 
a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py 
b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py
index 59373a8d00c03cf..ae4ee969f34d8b3 100644
--- a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py
+++ b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_ui.py
@@ -825,17 +825,34 @@ def test_get_all_lines_full_display(self):
 class TestLiveModeErrors(unittest.TestCase):
     """Tests running error commands in the live mode fails gracefully."""
 
+    class QuitWhenFinishedDisplay(MockDisplay):
+        def __init__(self, collector):
+            super().__init__()
+            self.collector = collector
+
+        def get_input(self):
+            ch = super().get_input()
+            if ch != -1:
+                return ch
+            # Sampling only stops once the target process has exited, at
+            # which point the collector is marked finished. Quit then so the
+            # run can surface the target's stderr. We must not rely on the
+            # target's pid still being signalable: once it exits it lingers
+            # as a zombie (it is reaped after sample_live returns), so a
+            # liveness check would never observe it gone and would hang.
+            if self.collector.finished:
+                return ord('q')
+            return -1
+
     def mock_curses_wrapper(self, func):
         func(mock.MagicMock())
 
     def mock_init_curses_side_effect(self, n_times, mock_self, stdscr):
-        mock_self.display = MockDisplay()
-        # Allow the loop to run for a bit (approx 0.5s) before quitting
-        # This ensures we don't exit too early while the subprocess is
-        # still failing
+        mock_self.display = self.QuitWhenFinishedDisplay(mock_self)
+        # Feed non-input events so live mode keeps polling while the target
+        # process is still running; once it exits the display quits on its own.
         for _ in range(n_times):
             mock_self.display.simulate_input(-1)
-        mock_self.display.simulate_input(ord('q'))
 
     def test_run_failed_module_live(self):
         """Test that running a existing module that fails exits with clean 
error."""
diff --git 
a/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst 
b/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst
new file mode 100644
index 000000000000000..3bbb471163d64e1
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2026-06-06-16-22-00.gh-issue-150966.7N9x5Q.rst
@@ -0,0 +1,2 @@
+Avoid prematurely terminating failing live sampling profiler test targets,
+which made stderr assertions flaky on ASAN buildbots.

_______________________________________________
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