https://github.com/python/cpython/commit/25468862c3b7bf6d37f857f6f2017851a431e274
commit: 25468862c3b7bf6d37f857f6f2017851a431e274
branch: 3.13
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-10T05:41:21Z
summary:

[3.13] gh-69134: Harden NotebookTest.test_traversal (GH-153403) (GH-153415)

identify(5, 5) could run before the notebook reached its requested size,
so the pixel fell outside the first tab and returned ''.  Guard it with a
new opt-in wait_until_mapped(full_size=True).
(cherry picked from commit 53b04980284b668c27fc6d5adb0de19d38efe95b)

Co-authored-by: Claude Opus 4.8 <[email protected]>

files:
M Lib/test/test_tkinter/support.py
M Lib/test/test_ttk/test_widgets.py

diff --git a/Lib/test/test_tkinter/support.py b/Lib/test/test_tkinter/support.py
index 84c83306e57ebae..ea2f9012a705498 100644
--- a/Lib/test/test_tkinter/support.py
+++ b/Lib/test/test_tkinter/support.py
@@ -93,7 +93,7 @@ def destroy_default_root():
         tkinter._default_root.destroy()
         tkinter._default_root = None
 
-def wait_until_mapped(widget, timeout=None):
+def wait_until_mapped(widget, timeout=None, *, full_size=False):
     """Wait until *widget* is actually mapped and laid out by the window
     manager, so that realized-geometry queries (winfo_width(), identify(),
     coords(), ...) return meaningful values.
@@ -103,6 +103,10 @@ def wait_until_mapped(widget, timeout=None):
     ``support.LOOPBACK_TIMEOUT``).  Unlike Misc.wait_visibility(), this
     never blocks indefinitely, so it is safe under a window manager that
     never maps the window (see gh-69134, gh-74941, bpo-40722).
+
+    If *full_size* is true, also wait until the realized size reaches the
+    requested size, so that per-pixel queries near an edge (e.g. identify())
+    are reliable even under load.
     """
     if timeout is None:
         timeout = support.LOOPBACK_TIMEOUT
@@ -110,10 +114,15 @@ def wait_until_mapped(widget, timeout=None):
     widget.update_idletasks()
     while True:
         widget.update()  # drain pending Map/Configure events
-        if (widget.winfo_ismapped()
-                and widget.winfo_width() > 1
-                and widget.winfo_height() > 1):
-            return True
+        if widget.winfo_ismapped():
+            if full_size:
+                w_ok = widget.winfo_width() >= widget.winfo_reqwidth() > 1
+                h_ok = widget.winfo_height() >= widget.winfo_reqheight() > 1
+            else:
+                w_ok = widget.winfo_width() > 1
+                h_ok = widget.winfo_height() > 1
+            if w_ok and h_ok:
+                return True
         if time.monotonic() >= deadline:
             return False
         time.sleep(0.01)
diff --git a/Lib/test/test_ttk/test_widgets.py 
b/Lib/test/test_ttk/test_widgets.py
index 5054ad8b9adf3fc..f134f88aedf6cbc 100644
--- a/Lib/test/test_ttk/test_widgets.py
+++ b/Lib/test/test_ttk/test_widgets.py
@@ -1192,8 +1192,16 @@ def test_traversal(self):
 
         self.nb.select(0)
 
-        focus_identify_as = 'focus' if sys.platform != 'darwin' else ''
-        self.assertEqual(self.nb.identify(5, 5), focus_identify_as)
+        if sys.platform == 'darwin':
+            focus_identify_as = ''
+        elif sys.platform == 'win32':
+            focus_identify_as = 'focus'
+        else:
+            focus_identify_as = 'focus' if tk_version < (8, 7) else 'padding'
+        # identify() at (5, 5) needs the tab realized there; under focus
+        # contention the mapped size can lag, so wait for the full size.
+        if wait_until_mapped(self.nb, full_size=True):
+            self.assertEqual(self.nb.identify(5, 5), focus_identify_as)
         simulate_mouse_click(self.nb, 5, 5)
         self.nb.focus_force()
         self.nb.event_generate('<Control-Tab>')
@@ -1209,7 +1217,8 @@ def test_traversal(self):
         self.nb.tab(self.child2, text='e', underline=0)
         self.nb.enable_traversal()
         self.nb.focus_force()
-        self.assertEqual(self.nb.identify(5, 5), focus_identify_as)
+        if wait_until_mapped(self.nb, full_size=True):
+            self.assertEqual(self.nb.identify(5, 5), focus_identify_as)
         simulate_mouse_click(self.nb, 5, 5)
         # on macOS Emacs-style keyboard shortcuts are region-dependent;
         # let's use the regular arrow keys instead

_______________________________________________
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