diff --git a/Lib/test/test_tkinter/support.py b/Lib/test/test_tkinter/support.py index 31feee2b8a40ee6..233a8f96ec46454 100644 --- a/Lib/test/test_tkinter/support.py +++ b/Lib/test/test_tkinter/support.py @@ -61,6 +61,16 @@ def require_mapped(self, widget, timeout=None): f'(timed out after {timeout:g}s)') +class AbstractDialogTest(AbstractTkTest): + # Tk delivers generated keyboard events to the window which has the + # focus. Hide the root window, otherwise the window manager can take + # the focus back from the dialog (gh-154357). + + def setUp(self): + super().setUp() + self.root.withdraw() + + class AbstractDefaultRootTest: def setUp(self): diff --git a/Lib/test/test_tkinter/test_filedialog.py b/Lib/test/test_tkinter/test_filedialog.py index f65ed19895a1ed4..c62b8c150e132d4 100644 --- a/Lib/test/test_tkinter/test_filedialog.py +++ b/Lib/test/test_tkinter/test_filedialog.py @@ -6,7 +6,7 @@ from tkinter.commondialog import Dialog from test.support import requires, swap_attr from test.test_tkinter.support import setUpModule # noqa: F401 -from test.test_tkinter.support import AbstractTkTest +from test.test_tkinter.support import AbstractDialogTest, AbstractTkTest requires('gui') @@ -72,7 +72,7 @@ def test_results_preserved(self): ('/a', '/b')) -class FileDialogTest(AbstractTkTest, unittest.TestCase): +class FileDialogTest(AbstractDialogTest, unittest.TestCase): # The pure-Python FileDialog runs its own modal loop in go(); its logic is # exercised here without entering the loop. diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index a225079dd99091b..b95b33943c731e7 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -17,7 +17,8 @@ from test.test_tkinter.support import setUpModule # noqa: F401 from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest, requires_tk, get_tk_patchlevel, - tcl_version, tk_version) + tcl_version, tk_version, + wait_until_mapped) support.requires('gui') @@ -1321,7 +1322,8 @@ def test_wm_stackorder(self): t2 = tkinter.Toplevel(self.root) t1.deiconify() t2.deiconify() - self.root.update() + wait_until_mapped(t1) + wait_until_mapped(t2) t1.lift(t2) # Raise t1 above t2. self.root.update() order = self.root.wm_stackorder() diff --git a/Lib/test/test_tkinter/test_simpledialog.py b/Lib/test/test_tkinter/test_simpledialog.py index be0be8d3f546311..10d0cce057ccf31 100644 --- a/Lib/test/test_tkinter/test_simpledialog.py +++ b/Lib/test/test_tkinter/test_simpledialog.py @@ -3,7 +3,7 @@ from tkinter import messagebox, ttk from test.support import requires, swap_attr from test.test_tkinter.support import setUpModule # noqa: F401 -from test.test_tkinter.support import AbstractDefaultRootTest, AbstractTkTest +from test.test_tkinter.support import AbstractDefaultRootTest, AbstractDialogTest from tkinter.simpledialog import (Dialog, SimpleDialog, askinteger, askfloat, askstring, _QueryInteger, _QueryFloat, _QueryString, @@ -12,7 +12,7 @@ requires('gui') -class SimpleDialogTest(AbstractTkTest, unittest.TestCase): +class SimpleDialogTest(AbstractDialogTest, unittest.TestCase): # SimpleDialog's modal loop is in go(); its bindings are exercised here by # generating events on the constructed dialog, without entering the loop. @@ -246,7 +246,7 @@ def test_go(self): self.assertEqual(d.go(), 0) -class DialogTest(AbstractTkTest, unittest.TestCase): +class DialogTest(AbstractDialogTest, unittest.TestCase): # Dialog's button box is modelled on tk::MessageBox. def open(self, **kw): @@ -432,7 +432,7 @@ def mock_wait_window(w): self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number") -class QueryDialogTest(AbstractTkTest, unittest.TestCase): +class QueryDialogTest(AbstractDialogTest, unittest.TestCase): # The query dialogs are modal: their __init__ blocks in wait_window(). # Mock that out so the dialog stays alive and can be driven with generated # events, exercising the / bindings and the validation. diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 4fa6a032e97c5f8..9fcde4d87c0b109 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -2024,19 +2024,23 @@ def test_virtual_events(self): lambda e: selects.append(self.tv.selection())) self.tv.bind('<>', lambda e: opens.append(self.tv.focus())) self.tv.bind('<>', lambda e: closes.append(self.tv.focus())) - self.tv.focus_force() self.tv.focus(parent) self.tv.selection_set(parent) self.tv.update() + # Force the focus right before generating the event: the window + # manager can take it back while the events are processed. + self.tv.focus_force() self.tv.event_generate('') # Open the focused parent. self.tv.update() self.assertEqual(opens, [parent]) + self.tv.focus_force() self.tv.event_generate('') # Close it again. self.tv.update() self.assertEqual(closes, [parent]) + self.tv.focus_force() self.tv.event_generate('') # Move the selection. self.tv.update() self.assertEqual(self.tv.selection(), (item2,))