From 3eb4d8e9ed3ceae4223fd996515a8b6b92baaa10 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 23 Nov 2020 12:15:21 +0200 Subject: [PATCH 1/5] bpo-42142: Fix timeouts in ttk tests Check whether the widget is already visible before waiting a event. --- Lib/tkinter/test/support.py | 4 ++++ Lib/tkinter/test/test_ttk/test_extensions.py | 14 ++++++------ Lib/tkinter/test/test_ttk/test_widgets.py | 24 ++++++++++---------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py index 467a0b66c265c0..e11ae5a434b2f0 100644 --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -115,3 +115,7 @@ def widget_eq(actual, expected): if isinstance(expected, (str, tkinter.Widget)): return str(actual) == str(expected) return False + +def show(widget): + if not widget.winfo_ismapped(): + widget.wait_visibility() diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py index a45f882bb00d48..a9759be2305e9d 100644 --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -3,7 +3,7 @@ import tkinter from tkinter import ttk from test.support import requires, run_unittest, swap_attr -from tkinter.test.support import AbstractTkTest, destroy_default_root +from tkinter.test.support import AbstractTkTest, destroy_default_root, show requires('gui') @@ -114,7 +114,7 @@ def check_positions(scale, scale_pos, label, label_pos): def test_horizontal_range(self): lscale = ttk.LabeledScale(self.root, from_=0, to=10) lscale.pack() - lscale.wait_visibility() + show(lscale) lscale.update() linfo_1 = lscale.label.place_info() @@ -144,7 +144,7 @@ def test_horizontal_range(self): def test_variable_change(self): x = ttk.LabeledScale(self.root) x.pack() - x.wait_visibility() + show(x) x.update() curr_xcoord = x.scale.coords()[0] @@ -187,7 +187,7 @@ def test_variable_change(self): def test_resize(self): x = ttk.LabeledScale(self.root) x.pack(expand=True, fill='both') - x.wait_visibility() + show(x) x.update() width, height = x.master.winfo_width(), x.master.winfo_height() @@ -268,7 +268,7 @@ def test_menu(self): # check that variable is updated correctly optmenu.pack() - optmenu.wait_visibility() + show(optmenu) optmenu['menu'].invoke(0) self.assertEqual(optmenu._variable.get(), items[0]) @@ -299,9 +299,9 @@ def test_unique_radiobuttons(self): textvar2 = tkinter.StringVar(self.root) optmenu2 = ttk.OptionMenu(self.root, textvar2, default, *items) optmenu.pack() - optmenu.wait_visibility() + show(optmenu) optmenu2.pack() - optmenu2.wait_visibility() + show(optmenu2) optmenu['menu'].invoke(1) optmenu2['menu'].invoke(2) optmenu_stringvar_name = optmenu['menu'].entrycget(0, 'variable') diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index 2598bc67652075..fd2154b9712bd5 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -6,7 +6,7 @@ from tkinter.test.test_ttk.test_functions import MockTclObj from tkinter.test.support import (AbstractTkTest, tcl_version, get_tk_patchlevel, - simulate_mouse_click) + simulate_mouse_click, show) from tkinter.test.widget_tests import (add_standard_options, noconv, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, setUpModule) @@ -60,7 +60,7 @@ def setUp(self): super().setUp() self.widget = ttk.Button(self.root, width=0, text="Text") self.widget.pack() - self.widget.wait_visibility() + show(self.widget) def test_identify(self): @@ -326,7 +326,7 @@ def test_bbox(self): def test_identify(self): self.entry.pack() - self.entry.wait_visibility() + show(self.entry) self.entry.update_idletasks() # bpo-27313: macOS Cocoa widget differs from X, allow either @@ -449,7 +449,7 @@ def test_virtual_event(self): self.combo.bind('<>', lambda evt: success.append(True)) self.combo.pack() - self.combo.wait_visibility() + show(self.combo) height = self.combo.winfo_height() self._show_drop_down_listbox() @@ -465,7 +465,7 @@ def test_postcommand(self): self.combo['postcommand'] = lambda: success.append(True) self.combo.pack() - self.combo.wait_visibility() + show(self.combo) self._show_drop_down_listbox() self.assertTrue(success) @@ -665,7 +665,7 @@ def test_sashpos(self): self.assertRaises(tkinter.TclError, self.paned.sashpos, 1) self.paned.pack(expand=True, fill='both') - self.paned.wait_visibility() + show(self.paned) curr_pos = self.paned.sashpos(0) self.paned.sashpos(0, 1000) @@ -933,7 +933,7 @@ def test_tab_identifiers(self): self.nb.add(self.child1, text='a') self.nb.pack() - self.nb.wait_visibility() + show(self.nb) if sys.platform == 'darwin': tb_idx = "@20,5" else: @@ -1041,7 +1041,7 @@ def test_insert(self): def test_select(self): self.nb.pack() - self.nb.wait_visibility() + show(self.nb) success = [] tab_changed = [] @@ -1084,7 +1084,7 @@ def test_tabs(self): def test_traversal(self): self.nb.pack() - self.nb.wait_visibility() + show(self.nb) self.nb.select(0) @@ -1342,7 +1342,7 @@ def test_show(self): def test_bbox(self): self.tv.pack() self.assertEqual(self.tv.bbox(''), '') - self.tv.wait_visibility() + show(self.tv) self.tv.update() item_id = self.tv.insert('', 'end') @@ -1536,7 +1536,7 @@ def simulate_heading_click(x, y): success = [] # no success for now self.tv.pack() - self.tv.wait_visibility() + show(self.tv) self.tv.heading('#0', command=lambda: success.append(True)) self.tv.column('#0', width=100) self.tv.update() @@ -1784,7 +1784,7 @@ def test_tag_bind(self): lambda evt: events.append(2)) self.tv.pack() - self.tv.wait_visibility() + show(self.tv) self.tv.update() pos_y = set() From c2f01364e6b255c8b8070ffc80cb935bbbb80087 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 23 Nov 2020 16:41:31 +0200 Subject: [PATCH 2/5] Ensure that the correct element is clicked. --- Lib/tkinter/test/support.py | 2 ++ Lib/tkinter/test/test_ttk/test_widgets.py | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py index e11ae5a434b2f0..70b4d27dd2e8a8 100644 --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -119,3 +119,5 @@ def widget_eq(actual, expected): def show(widget): if not widget.winfo_ismapped(): widget.wait_visibility() + else: + print(f"Widget {widget} is already mapped") diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index fd2154b9712bd5..d0a417785b8fcd 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -437,8 +437,10 @@ def test_height(self): def _show_drop_down_listbox(self): width = self.combo.winfo_width() - self.combo.event_generate('', x=width - 5, y=5) - self.combo.event_generate('', x=width - 5, y=5) + x, y = width - 5, 5 + self.assertEqual(self.combo.identify(x, y), 'downarrow') + self.combo.event_generate('', x=x, y=y) + self.combo.event_generate('', x=x, y=y) self.combo.update_idletasks() @@ -1132,6 +1134,7 @@ def _click_increment_arrow(self): height = self.spin.winfo_height() x = width - 5 y = height//2 - 5 + self.assertEqual(self.spin.identify(x, y), 'uparrow') self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() @@ -1141,6 +1144,7 @@ def _click_decrement_arrow(self): height = self.spin.winfo_height() x = width - 5 y = height//2 + 4 + self.assertEqual(self.spin.identify(x, y), 'downarrow') self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() From 3eaaf33cdf729b3a4842ff24aef26b63c63216bd Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 23 Nov 2020 17:36:13 +0200 Subject: [PATCH 3/5] Fix checks on Windows. --- Lib/tkinter/test/test_ttk/test_widgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index d0a417785b8fcd..3425663b1259ae 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -438,7 +438,7 @@ def test_height(self): def _show_drop_down_listbox(self): width = self.combo.winfo_width() x, y = width - 5, 5 - self.assertEqual(self.combo.identify(x, y), 'downarrow') + self.assertRegex(self.combo.identify(x, y), r'.*downarrow\Z') self.combo.event_generate('', x=x, y=y) self.combo.event_generate('', x=x, y=y) self.combo.update_idletasks() @@ -1134,7 +1134,7 @@ def _click_increment_arrow(self): height = self.spin.winfo_height() x = width - 5 y = height//2 - 5 - self.assertEqual(self.spin.identify(x, y), 'uparrow') + self.assertRegex(self.spin.identify(x, y), r'.*uparrow\Z') self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() @@ -1144,7 +1144,7 @@ def _click_decrement_arrow(self): height = self.spin.winfo_height() x = width - 5 y = height//2 + 4 - self.assertEqual(self.spin.identify(x, y), 'downarrow') + self.assertRegex(self.spin.identify(x, y), r'.*downarrow\Z') self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() From 906a332562b8760b9ef57e24095ce31caec1676c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 23 Nov 2020 21:52:37 +0200 Subject: [PATCH 4/5] Use update_idletasks() instead of wait_visibility() --- Lib/tkinter/test/support.py | 8 +++---- Lib/tkinter/test/test_ttk/test_extensions.py | 14 ++++++------ Lib/tkinter/test/test_ttk/test_widgets.py | 24 ++++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py index 70b4d27dd2e8a8..4bb40ddf4d78d8 100644 --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -116,8 +116,8 @@ def widget_eq(actual, expected): return str(actual) == str(expected) return False -def show(widget): +def show_widget(widget): if not widget.winfo_ismapped(): - widget.wait_visibility() - else: - print(f"Widget {widget} is already mapped") + widget.update_idletasks() + if not widget.winfo_ismapped(): + raise RuntimeError(f"Widget {widget} is still not mapped") diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py index a9759be2305e9d..a82bddc9f2831d 100644 --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -3,7 +3,7 @@ import tkinter from tkinter import ttk from test.support import requires, run_unittest, swap_attr -from tkinter.test.support import AbstractTkTest, destroy_default_root, show +from tkinter.test.support import AbstractTkTest, destroy_default_root, show_widget requires('gui') @@ -114,7 +114,7 @@ def check_positions(scale, scale_pos, label, label_pos): def test_horizontal_range(self): lscale = ttk.LabeledScale(self.root, from_=0, to=10) lscale.pack() - show(lscale) + show_widget(lscale) lscale.update() linfo_1 = lscale.label.place_info() @@ -144,7 +144,7 @@ def test_horizontal_range(self): def test_variable_change(self): x = ttk.LabeledScale(self.root) x.pack() - show(x) + show_widget(x) x.update() curr_xcoord = x.scale.coords()[0] @@ -187,7 +187,7 @@ def test_variable_change(self): def test_resize(self): x = ttk.LabeledScale(self.root) x.pack(expand=True, fill='both') - show(x) + show_widget(x) x.update() width, height = x.master.winfo_width(), x.master.winfo_height() @@ -268,7 +268,7 @@ def test_menu(self): # check that variable is updated correctly optmenu.pack() - show(optmenu) + show_widget(optmenu) optmenu['menu'].invoke(0) self.assertEqual(optmenu._variable.get(), items[0]) @@ -299,9 +299,9 @@ def test_unique_radiobuttons(self): textvar2 = tkinter.StringVar(self.root) optmenu2 = ttk.OptionMenu(self.root, textvar2, default, *items) optmenu.pack() - show(optmenu) + show_widget(optmenu) optmenu2.pack() - show(optmenu2) + show_widget(optmenu2) optmenu['menu'].invoke(1) optmenu2['menu'].invoke(2) optmenu_stringvar_name = optmenu['menu'].entrycget(0, 'variable') diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index 3425663b1259ae..1fb4c9762b067f 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -6,7 +6,7 @@ from tkinter.test.test_ttk.test_functions import MockTclObj from tkinter.test.support import (AbstractTkTest, tcl_version, get_tk_patchlevel, - simulate_mouse_click, show) + simulate_mouse_click, show_widget) from tkinter.test.widget_tests import (add_standard_options, noconv, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, setUpModule) @@ -60,7 +60,7 @@ def setUp(self): super().setUp() self.widget = ttk.Button(self.root, width=0, text="Text") self.widget.pack() - show(self.widget) + show_widget(self.widget) def test_identify(self): @@ -326,7 +326,7 @@ def test_bbox(self): def test_identify(self): self.entry.pack() - show(self.entry) + show_widget(self.entry) self.entry.update_idletasks() # bpo-27313: macOS Cocoa widget differs from X, allow either @@ -451,7 +451,7 @@ def test_virtual_event(self): self.combo.bind('<>', lambda evt: success.append(True)) self.combo.pack() - show(self.combo) + show_widget(self.combo) height = self.combo.winfo_height() self._show_drop_down_listbox() @@ -467,7 +467,7 @@ def test_postcommand(self): self.combo['postcommand'] = lambda: success.append(True) self.combo.pack() - show(self.combo) + show_widget(self.combo) self._show_drop_down_listbox() self.assertTrue(success) @@ -667,7 +667,7 @@ def test_sashpos(self): self.assertRaises(tkinter.TclError, self.paned.sashpos, 1) self.paned.pack(expand=True, fill='both') - show(self.paned) + show_widget(self.paned) curr_pos = self.paned.sashpos(0) self.paned.sashpos(0, 1000) @@ -935,7 +935,7 @@ def test_tab_identifiers(self): self.nb.add(self.child1, text='a') self.nb.pack() - show(self.nb) + show_widget(self.nb) if sys.platform == 'darwin': tb_idx = "@20,5" else: @@ -1043,7 +1043,7 @@ def test_insert(self): def test_select(self): self.nb.pack() - show(self.nb) + show_widget(self.nb) success = [] tab_changed = [] @@ -1086,7 +1086,7 @@ def test_tabs(self): def test_traversal(self): self.nb.pack() - show(self.nb) + show_widget(self.nb) self.nb.select(0) @@ -1346,7 +1346,7 @@ def test_show(self): def test_bbox(self): self.tv.pack() self.assertEqual(self.tv.bbox(''), '') - show(self.tv) + show_widget(self.tv) self.tv.update() item_id = self.tv.insert('', 'end') @@ -1540,7 +1540,7 @@ def simulate_heading_click(x, y): success = [] # no success for now self.tv.pack() - show(self.tv) + show_widget(self.tv) self.tv.heading('#0', command=lambda: success.append(True)) self.tv.column('#0', width=100) self.tv.update() @@ -1788,7 +1788,7 @@ def test_tag_bind(self): lambda evt: events.append(2)) self.tv.pack() - show(self.tv) + show_widget(self.tv) self.tv.update() pos_y = set() From 02dedbe8c120800fa8d5ee0cdc7d1d099263ffcd Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 25 Nov 2020 00:12:41 +0200 Subject: [PATCH 5/5] Don't use winfo_ismapped(). Use update() if neccessary. --- Lib/tkinter/test/support.py | 6 ------ Lib/tkinter/test/test_ttk/test_extensions.py | 8 +------ Lib/tkinter/test/test_ttk/test_widgets.py | 22 +++++++------------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py index 4bb40ddf4d78d8..467a0b66c265c0 100644 --- a/Lib/tkinter/test/support.py +++ b/Lib/tkinter/test/support.py @@ -115,9 +115,3 @@ def widget_eq(actual, expected): if isinstance(expected, (str, tkinter.Widget)): return str(actual) == str(expected) return False - -def show_widget(widget): - if not widget.winfo_ismapped(): - widget.update_idletasks() - if not widget.winfo_ismapped(): - raise RuntimeError(f"Widget {widget} is still not mapped") diff --git a/Lib/tkinter/test/test_ttk/test_extensions.py b/Lib/tkinter/test/test_ttk/test_extensions.py index a82bddc9f2831d..6937ba1ca9be41 100644 --- a/Lib/tkinter/test/test_ttk/test_extensions.py +++ b/Lib/tkinter/test/test_ttk/test_extensions.py @@ -3,7 +3,7 @@ import tkinter from tkinter import ttk from test.support import requires, run_unittest, swap_attr -from tkinter.test.support import AbstractTkTest, destroy_default_root, show_widget +from tkinter.test.support import AbstractTkTest, destroy_default_root requires('gui') @@ -114,7 +114,6 @@ def check_positions(scale, scale_pos, label, label_pos): def test_horizontal_range(self): lscale = ttk.LabeledScale(self.root, from_=0, to=10) lscale.pack() - show_widget(lscale) lscale.update() linfo_1 = lscale.label.place_info() @@ -144,7 +143,6 @@ def test_horizontal_range(self): def test_variable_change(self): x = ttk.LabeledScale(self.root) x.pack() - show_widget(x) x.update() curr_xcoord = x.scale.coords()[0] @@ -187,7 +185,6 @@ def test_variable_change(self): def test_resize(self): x = ttk.LabeledScale(self.root) x.pack(expand=True, fill='both') - show_widget(x) x.update() width, height = x.master.winfo_width(), x.master.winfo_height() @@ -268,7 +265,6 @@ def test_menu(self): # check that variable is updated correctly optmenu.pack() - show_widget(optmenu) optmenu['menu'].invoke(0) self.assertEqual(optmenu._variable.get(), items[0]) @@ -299,9 +295,7 @@ def test_unique_radiobuttons(self): textvar2 = tkinter.StringVar(self.root) optmenu2 = ttk.OptionMenu(self.root, textvar2, default, *items) optmenu.pack() - show_widget(optmenu) optmenu2.pack() - show_widget(optmenu2) optmenu['menu'].invoke(1) optmenu2['menu'].invoke(2) optmenu_stringvar_name = optmenu['menu'].entrycget(0, 'variable') diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py index 2981b373a76c3d..157ef0e8f87bb5 100644 --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -6,7 +6,7 @@ from tkinter.test.test_ttk.test_functions import MockTclObj from tkinter.test.support import (AbstractTkTest, tcl_version, get_tk_patchlevel, - simulate_mouse_click, show_widget) + simulate_mouse_click) from tkinter.test.widget_tests import (add_standard_options, noconv, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, setUpModule) @@ -60,11 +60,10 @@ def setUp(self): super().setUp() self.widget = ttk.Button(self.root, width=0, text="Text") self.widget.pack() - show_widget(self.widget) def test_identify(self): - self.widget.update_idletasks() + self.widget.update() self.assertEqual(self.widget.identify( int(self.widget.winfo_width() / 2), int(self.widget.winfo_height() / 2) @@ -326,8 +325,7 @@ def test_bbox(self): def test_identify(self): self.entry.pack() - show_widget(self.entry) - self.entry.update_idletasks() + self.entry.update() # bpo-27313: macOS Cocoa widget differs from X, allow either if sys.platform == 'darwin': @@ -450,7 +448,7 @@ def test_virtual_event(self): self.combo.bind('<>', lambda evt: success.append(True)) self.combo.pack() - show_widget(self.combo) + self.combo.update() height = self.combo.winfo_height() self._show_drop_down_listbox() @@ -466,7 +464,7 @@ def test_postcommand(self): self.combo['postcommand'] = lambda: success.append(True) self.combo.pack() - show_widget(self.combo) + self.combo.update() self._show_drop_down_listbox() self.assertTrue(success) @@ -666,7 +664,6 @@ def test_sashpos(self): self.assertRaises(tkinter.TclError, self.paned.sashpos, 1) self.paned.pack(expand=True, fill='both') - show_widget(self.paned) curr_pos = self.paned.sashpos(0) self.paned.sashpos(0, 1000) @@ -934,7 +931,7 @@ def test_tab_identifiers(self): self.nb.add(self.child1, text='a') self.nb.pack() - show_widget(self.nb) + self.nb.update() if sys.platform == 'darwin': tb_idx = "@20,5" else: @@ -1042,7 +1039,7 @@ def test_insert(self): def test_select(self): self.nb.pack() - show_widget(self.nb) + self.nb.update() success = [] tab_changed = [] @@ -1085,7 +1082,7 @@ def test_tabs(self): def test_traversal(self): self.nb.pack() - show_widget(self.nb) + self.nb.update() self.nb.select(0) @@ -1347,7 +1344,6 @@ def test_show(self): def test_bbox(self): self.tv.pack() self.assertEqual(self.tv.bbox(''), '') - show_widget(self.tv) self.tv.update() item_id = self.tv.insert('', 'end') @@ -1544,7 +1540,6 @@ def simulate_heading_click(x, y): success = [] # no success for now self.tv.pack() - show_widget(self.tv) self.tv.heading('#0', command=lambda: success.append(True)) self.tv.column('#0', width=100) self.tv.update() @@ -1792,7 +1787,6 @@ def test_tag_bind(self): lambda evt: events.append(2)) self.tv.pack() - show_widget(self.tv) self.tv.update() pos_y = set()