From deef96797dda3082f2a606fa6cd5ecbb566fb6c4 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 28 May 2023 21:18:56 -0400 Subject: [PATCH 01/30] gh-104855: Update more tk tests for 8.7 Where applicable: * Add '' to the valid options in error messages. * Test that '' is valid. * Test that 'to' < 'from' is valid instead of invalid. This PR also fixes gh-104856. --- .../test_tkinter/test_geometry_managers.py | 11 +++++++---- Lib/test/test_tkinter/test_widgets.py | 16 ++++++++++++---- Lib/test/test_tkinter/widget_tests.py | 18 ++++++++++++------ ...3-05-28-21-12-44.gh-issue-104855.viuQsR.rst | 3 +++ 4 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index 59fe592b492adc..de1764fc5335c4 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -405,6 +405,11 @@ def test_place_configure_height(self): with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): f2.place_configure(height='abcd') + def place_err(self, root): + tk86 = root.info_patchlevel() < (8, 7) + return ('expected floating-point number ' + f'''{'' if tk86 else 'or "" '}but got "abcd"''') + def test_place_configure_relwidth(self): t, f, f2 = self.create2() f2.place_configure(in_=f, relwidth=0.5) @@ -413,8 +418,7 @@ def test_place_configure_relwidth(self): f2.place_configure(relwidth='') self.root.update() self.assertEqual(f2.winfo_width(), 30) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "abcd"'): + with self.assertRaisesRegex(TclError, self.place_err(self.root)): f2.place_configure(relwidth='abcd') def test_place_configure_relheight(self): @@ -425,8 +429,7 @@ def test_place_configure_relheight(self): f2.place_configure(relheight='') self.root.update() self.assertEqual(f2.winfo_height(), 60) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "abcd"'): + with self.assertRaisesRegex(TclError, self.place_err(self.root)): f2.place_configure(relheight='abcd') def test_place_configure_bordermode(self): diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 34e67c0cbc44a3..21f221305e8599 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -489,8 +489,12 @@ def test_configure_from(self): widget = self.create() self.checkParam(widget, 'to', 100.0) self.checkFloatParam(widget, 'from', -10, 10.2, 11.7) - self.checkInvalidParam(widget, 'from', 200, - errmsg='-to value must be greater than -from value') + if widget.info_patchlevel() < (8, 7): + self.checkInvalidParam( + widget, 'from', 200, + errmsg='-to value must be greater than -from value') + else: + self.checkFloatParam(widget, 'from', 200) def test_configure_increment(self): widget = self.create() @@ -500,8 +504,12 @@ def test_configure_to(self): widget = self.create() self.checkParam(widget, 'from', -100.0) self.checkFloatParam(widget, 'to', -10, 10.2, 11.7) - self.checkInvalidParam(widget, 'to', -200, - errmsg='-to value must be greater than -from value') + if widget.info_patchlevel() < (8, 7): + self.checkInvalidParam( + widget, 'to', -200, + errmsg='-to value must be greater than -from value') + else: + self.checkFloatParam(widget, 'to', -200) def test_configure_values(self): # XXX diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index f60087a6e9f385..e7a8ce3f5b88cf 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -74,8 +74,11 @@ def checkParams(self, widget, name, *values, **kwargs): def checkIntegerParam(self, widget, name, *values, **kwargs): self.checkParams(widget, name, *values, **kwargs) - self.checkInvalidParam(widget, name, '', - errmsg='expected integer but got ""') + if tcl_version < (8, 7) or name == 'underline': + self.checkInvalidParam(widget, name, '', + errmsg='expected integer but got ""') + else: + self.checkParams(widget, 'underline', '') self.checkInvalidParam(widget, name, '10p', errmsg='expected integer but got "10p"') self.checkInvalidParam(widget, name, 3.2, @@ -152,10 +155,13 @@ def checkPixelsParam(self, widget, name, *values, errmsg='bad screen distance "spam"') def checkReliefParam(self, widget, name): - self.checkParams(widget, name, - 'flat', 'groove', 'raised', 'ridge', 'solid', 'sunken') - errmsg='bad relief "spam": must be '\ - 'flat, groove, raised, ridge, solid, or sunken' + options = ['flat', 'groove', 'raised', 'ridge', 'solid', 'sunken'] + if tcl_version >= (8, 7) and name in ('overrelief', 'proxyrelief'): + options.append('') + self.checkParams(widget, name, *options) + lastop = options.pop() + opstring = ', '.join(options) + errmsg=f'bad relief "spam": must be {opstring}, or {lastop}' if tcl_version < (8, 6): errmsg = None self.checkInvalidParam(widget, name, 'spam', diff --git a/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst b/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst new file mode 100644 index 00000000000000..c0d396488e14eb --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst @@ -0,0 +1,3 @@ +Where applicable update tkinter tests for 8.7 by adding '' to options in +error messages, testing '' for validity, and testing acceptance of 'to' +value < 'from' value in a spinbox (which switches the values). From 358bb7474b33ee059aca7e1b429a6087eab8204c Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 28 May 2023 21:34:09 -0400 Subject: [PATCH 02/30] whitespace --- Lib/test/test_tkinter/test_widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 21f221305e8599..f7001ae4adfb5e 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -489,7 +489,7 @@ def test_configure_from(self): widget = self.create() self.checkParam(widget, 'to', 100.0) self.checkFloatParam(widget, 'from', -10, 10.2, 11.7) - if widget.info_patchlevel() < (8, 7): + if widget.info_patchlevel() < (8, 7): self.checkInvalidParam( widget, 'from', 200, errmsg='-to value must be greater than -from value') From 11629b8b43fc2952ce5f330e89bd38396e58d79b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 31 May 2024 15:08:54 +0300 Subject: [PATCH 03/30] Fix errmsg for the last empty value. --- Lib/test/test_tkinter/widget_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index cb5c159eb6f102..f3d5eca8f271e4 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -161,7 +161,7 @@ def checkReliefParam(self, widget, name): self.checkParams(widget, name, *options) lastop = options.pop() opstring = ', '.join(options) - errmsg=f'bad relief "spam": must be {opstring}, or {lastop}' + errmsg = f'bad relief "spam": must be {opstring}, or {lastop or '""'}' if tk_version < (8, 6): errmsg = None self.checkInvalidParam(widget, name, 'spam', From 907abd022be264615cfa9fa8fbe820797ee9477d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 31 May 2024 19:31:06 +0300 Subject: [PATCH 04/30] Simplify the errmsg for place_configure(). --- Lib/test/test_tkinter/test_geometry_managers.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index 742565cc9936f3..92951de8f4e697 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -405,11 +405,6 @@ def test_place_configure_height(self): with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): f2.place_configure(height='abcd') - def place_err(self, root): - tk86 = root.info_patchlevel() < (8, 7) - return ('expected floating-point number ' - f'''{'' if tk86 else 'or "" '}but got "abcd"''') - def test_place_configure_relwidth(self): t, f, f2 = self.create2() f2.place_configure(in_=f, relwidth=0.5) @@ -418,7 +413,8 @@ def test_place_configure_relwidth(self): f2.place_configure(relwidth='') self.root.update() self.assertEqual(f2.winfo_width(), 30) - with self.assertRaisesRegex(TclError, self.place_err(self.root)): + with self.assertRaisesRegex(TclError, 'expected floating-point number ' + '(or "" )?but got "abcd"'): f2.place_configure(relwidth='abcd') def test_place_configure_relheight(self): @@ -429,7 +425,8 @@ def test_place_configure_relheight(self): f2.place_configure(relheight='') self.root.update() self.assertEqual(f2.winfo_height(), 60) - with self.assertRaisesRegex(TclError, self.place_err(self.root)): + with self.assertRaisesRegex(TclError, 'expected floating-point number ' + '(or "" )?but got "abcd"'): f2.place_configure(relheight='abcd') def test_place_configure_bordermode(self): From a1279f396ecafc225b4b5e004ecfc1f6efaea5f5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 31 May 2024 20:21:32 +0300 Subject: [PATCH 05/30] Fix fixes for options -underline, -to and -from. --- Lib/test/test_tkinter/test_widgets.py | 4 ++-- Lib/test/test_tkinter/widget_tests.py | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 0c0febf64c3d1b..07a58d8a66cabe 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -494,7 +494,7 @@ def test_configure_from(self): widget, 'from', 200, errmsg='-to value must be greater than -from value') else: - self.checkFloatParam(widget, 'from', 200) + self.checkFloatParam(widget, 'from', 100) def test_configure_increment(self): widget = self.create() @@ -509,7 +509,7 @@ def test_configure_to(self): widget, 'to', -200, errmsg='-to value must be greater than -from value') else: - self.checkFloatParam(widget, 'to', -200) + self.checkFloatParam(widget, 'to', -100) def test_configure_values(self): # XXX diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index f3d5eca8f271e4..e12de5e599ff9c 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -74,15 +74,11 @@ def checkParams(self, widget, name, *values, **kwargs): def checkIntegerParam(self, widget, name, *values, **kwargs): self.checkParams(widget, name, *values, **kwargs) - if tk_version < (8, 7) or name == 'underline': - self.checkInvalidParam(widget, name, '', - errmsg='expected integer but got ""') - else: - self.checkParams(widget, 'underline', '') - self.checkInvalidParam(widget, name, '10p', - errmsg='expected integer but got "10p"') - self.checkInvalidParam(widget, name, 3.2, - errmsg='expected integer but got "3.2"') + self.checkInvalidParam(widget, name, '', + errmsg='expected integer but got ""') + errmsg = 'expected integer but got "{}"' + self.checkInvalidParam(widget, name, '10p', errmsg=errmsg) + self.checkInvalidParam(widget, name, 3.2, errmsg=errmsg) def checkFloatParam(self, widget, name, *values, conv=float, **kwargs): for value in values: @@ -421,7 +417,15 @@ def test_configure_troughcolor(self): def test_configure_underline(self): widget = self.create() - self.checkIntegerParam(widget, 'underline', 0, 1, 10) + if tk_version >= (8, 7): + self.checkParams(widget, 'underline', 0, 1, 10) + self.checkParam(widget, 'underline', '', expected=-1) + errmsg = ('bad index "{}": must be integer?[+-]integer?, ' + 'end?[+-]integer?, or ""') + self.checkInvalidParam(widget, 'underline', '10p', errmsg=errmsg) + self.checkInvalidParam(widget, 'underline', 3.2, errmsg=errmsg) + else: + self.checkIntegerParam(widget, 'underline', 0, 1, 10) def test_configure_wraplength(self): widget = self.create() From f90b94dbe6341a4e8446dd3a89b9955ee79b9e45 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 31 May 2024 20:51:17 +0300 Subject: [PATCH 06/30] Fix test_create_polygon. --- Lib/test/test_tkinter/test_widgets.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 07a58d8a66cabe..a72c2b2490ffc4 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -4,7 +4,7 @@ import os from test.support import requires -from test.test_tkinter.support import (requires_tk, +from test.test_tkinter.support import (requires_tk, tk_version, get_tk_patchlevel, widget_eq, AbstractDefaultRootTest) from test.test_tkinter.widget_tests import ( @@ -868,24 +868,29 @@ def test_create_line(self): def test_create_polygon(self): c = self.create() + tk87 = tk_version >= (8, 7) i1 = c.create_polygon(20, 30, 40, 50, 60, 10) self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) - self.assertEqual(c.bbox(i1), (19, 9, 61, 51)) + self.assertEqual(c.bbox(i1), + (18, 8, 62, 52) if tk87 else (19, 9, 61, 51)) self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') self.assertEqual(c.itemcget(i1, 'smooth'), '0') self.assertEqual(c.itemcget(i1, 'splinestep'), '12') i2 = c.create_polygon([21, 31, 41, 51, 61, 11]) self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) - self.assertEqual(c.bbox(i2), (20, 10, 62, 52)) + self.assertEqual(c.bbox(i2), + (19, 9, 63, 53) if tk87 else (20, 10, 62, 52)) i3 = c.create_polygon((22, 32), (42, 52), (62, 12)) self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) - self.assertEqual(c.bbox(i3), (21, 11, 63, 53)) + self.assertEqual(c.bbox(i3), + (20, 10, 64, 54) if tk87 else (21, 11, 63, 53)) i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)]) self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) - self.assertEqual(c.bbox(i4), (22, 12, 64, 54)) + self.assertEqual(c.bbox(i4), + (21, 11, 65, 55) if tk87 else (22, 12, 64, 54)) self.assertRaises(TclError, c.create_polygon, 20, 30, 60) self.assertRaises(TclError, c.create_polygon, [20, 30, 60]) From 6ccd8feb1fd16a0b25842a97f29b9b4a0d83039d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2024 00:01:48 +0300 Subject: [PATCH 07/30] Fix more tests. --- Lib/test/test_tkinter/test_widgets.py | 3 +- Lib/test/test_tkinter/widget_tests.py | 11 +-- Lib/test/test_ttk/test_widgets.py | 104 ++++++++++++++++++++++---- 3 files changed, 97 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index a72c2b2490ffc4..be552483ef4df0 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1269,7 +1269,8 @@ def test_configure_proxyborderwidth(self): @requires_tk(8, 6, 5) def test_configure_proxyrelief(self): widget = self.create() - self.checkReliefParam(widget, 'proxyrelief') + self.checkReliefParam(widget, 'proxyrelief', + allow_empty=(tk_version >= (8, 7))) def test_configure_sashcursor(self): widget = self.create() diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index e12de5e599ff9c..0aed277af4cb60 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -150,9 +150,9 @@ def checkPixelsParam(self, widget, name, *values, self.checkInvalidParam(widget, name, 'spam', errmsg='bad screen distance "spam"') - def checkReliefParam(self, widget, name): + def checkReliefParam(self, widget, name, *, allow_empty=False): options = ['flat', 'groove', 'raised', 'ridge', 'solid', 'sunken'] - if tk_version >= (8, 7) and name in ('overrelief', 'proxyrelief'): + if allow_empty: options.append('') self.checkParams(widget, name, *options) lastop = options.pop() @@ -415,11 +415,11 @@ def test_configure_troughcolor(self): widget = self.create() self.checkColorParam(widget, 'troughcolor') - def test_configure_underline(self): + def test_configure_underline(self, *, empty_value=-1): widget = self.create() if tk_version >= (8, 7): self.checkParams(widget, 'underline', 0, 1, 10) - self.checkParam(widget, 'underline', '', expected=-1) + self.checkParam(widget, 'underline', '', expected=empty_value) errmsg = ('bad index "{}": must be integer?[+-]integer?, ' 'end?[+-]integer?, or ""') self.checkInvalidParam(widget, 'underline', '10p', errmsg=errmsg) @@ -455,7 +455,8 @@ def test_configure_offrelief(self): def test_configure_overrelief(self): widget = self.create() - self.checkReliefParam(widget, 'overrelief') + self.checkReliefParam(widget, 'overrelief', + allow_empty=(tk_version >= (8, 7))) def test_configure_selectcolor(self): widget = self.create() diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 2e0702da5448a8..5a041e82da359d 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -57,6 +57,9 @@ def test_configure_style(self): self.assertEqual(widget2['class'], 'Foo') # XXX + def test_configure_underline(self): + StandardOptionsTests.test_configure_underline(self, empty_value='') + class WidgetTest(AbstractTkTest, unittest.TestCase): """Tests methods available in every ttk widget.""" @@ -129,6 +132,11 @@ class FrameTest(AbstractToplevelTest, unittest.TestCase): def create(self, **kwargs): return ttk.Frame(self.root, **kwargs) + def test_configure_relief(self): + widget = self.create() + self.checkReliefParam(widget, 'relief', + allow_empty=(tk_version >= (8, 7))) + @add_standard_options(StandardTtkOptionsTests) class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): @@ -155,6 +163,11 @@ def test_configure_labelwidget(self): self.checkParam(widget, 'labelwidget', label, expected='.foo') label.destroy() + def test_configure_relief(self): + widget = self.create() + self.checkReliefParam(widget, 'relief', + allow_empty=(tk_version >= (8, 7))) + class AbstractLabelTest(AbstractWidgetTest): @@ -173,9 +186,11 @@ def checkImageParam(self, widget, name): def test_configure_compound(self): options = 'none text image center top bottom left right'.split() + if tk_version >= (8, 7): + options.append('') errmsg = ( 'bad compound "{}": must be' - f' {", ".join(options[:-1])}, or {options[-1]}' + f' {", ".join(options[:-1])}, or {options[-1] or '""'}' ) widget = self.create() self.checkEnumParam(widget, 'compound', *options, errmsg=errmsg) @@ -208,6 +223,11 @@ def test_configure_font(self): self.checkParam(widget, 'font', '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') + def test_configure_relief(self): + widget = self.create() + self.checkReliefParam(widget, 'relief', + allow_empty=(tk_version >= (8, 7))) + @add_standard_options(StandardTtkOptionsTests) class ButtonTest(AbstractLabelTest, unittest.TestCase): @@ -223,7 +243,11 @@ def create(self, **kwargs): def test_configure_default(self): widget = self.create() - self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled') + if tk_version >= (8, 7): + values = ('active', 'disabled', 'normal') + else: + values = ('normal', 'active', 'disabled') + self.checkEnumParam(widget, 'default', *values) def test_invoke(self): success = [] @@ -616,18 +640,27 @@ def test_add(self): other_child = ttk.Label(self.paned) self.paned.add(other_child) self.assertEqual(self.paned.pane(0), self.paned.pane(1)) - self.assertRaises(tkinter.TclError, self.paned.pane, 2) + if tk_version >= (8, 7): + self.assertEqual(self.paned.pane(2), self.paned.pane(1)) + else: + self.assertRaises(tkinter.TclError, self.paned.pane, 2) good_child.destroy() other_child.destroy() - self.assertRaises(tkinter.TclError, self.paned.pane, 0) + if tk_version < (8, 7): + # BUG: Crash in Tk 8.7b1 + self.assertRaises(tkinter.TclError, self.paned.pane, 0) def test_forget(self): - self.assertRaises(tkinter.TclError, self.paned.forget, None) - self.assertRaises(tkinter.TclError, self.paned.forget, 0) + if tk_version < (8, 7): + # BUG: Crash in Tk 8.7b1 + self.assertRaises(tkinter.TclError, self.paned.forget, None) + self.assertRaises(tkinter.TclError, self.paned.forget, 0) self.paned.add(ttk.Label(self.root)) self.paned.forget(0) - self.assertRaises(tkinter.TclError, self.paned.forget, 0) + if tk_version < (8, 7): + # BUG: Crash in Tk 8.7b1 + self.assertRaises(tkinter.TclError, self.paned.forget, 0) def test_insert(self): self.assertRaises(tkinter.TclError, self.paned.insert, None, 0) @@ -638,8 +671,14 @@ def test_insert(self): child2 = ttk.Label(self.root) child3 = ttk.Label(self.root) - self.assertRaises(tkinter.TclError, self.paned.insert, 0, child) + if tk_version >= (8, 7): + self.paned.insert(0, child) + self.assertEqual(self.paned.panes(), (str(child),)) + self.paned.forget(0) + else: + self.assertRaises(tkinter.TclError, self.paned.insert, 0, child) + self.assertEqual(self.paned.panes(), ()) self.paned.insert('end', child2) self.paned.insert(0, child) self.assertEqual(self.paned.panes(), (str(child), str(child2))) @@ -664,7 +703,9 @@ def test_insert(self): (str(child3), str(child2), str(child))) def test_pane(self): - self.assertRaises(tkinter.TclError, self.paned.pane, 0) + if tk_version < (8, 7): + # BUG: Crash in Tk 8.7b1 + self.assertRaises(tkinter.TclError, self.paned.pane, 0) child = ttk.Label(self.root) self.paned.add(child) @@ -742,7 +783,10 @@ def cb_test(): cbtn2['command'] = '' res = cbtn2.invoke() - self.assertEqual(str(res), '') + if tk_version >= (8, 7): + self.assertEqual(res, ()) + else: + self.assertEqual(str(res), '') self.assertLessEqual(len(success), 1) self.assertEqual(conv(cbtn2['value']), myvar.get()) self.assertEqual(myvar.get(), @@ -945,6 +989,22 @@ def setUp(self): def create(self, **kwargs): return ttk.Notebook(self.root, **kwargs) + def test_configure_height(self): + widget = self.create() + if tk_version >= (8, 7): + self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False) + self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=False) + else: + self.checkIntegerParam(widget, 'height', 100, -100, 0) + + def test_configure_width(self): + widget = self.create() + if tk_version >= (8, 7): + self.checkPixelsParam(widget, 'width', 402, -402, 0, '3c', conv=False) + self.checkPixelsParam(widget, 'height', 401.2, 402.6, conv=False) + else: + self.checkIntegerParam(widget, 'width', 402, -402, 0) + def test_tab_identifiers(self): self.nb.forget(0) self.nb.hide(self.child2) @@ -1039,7 +1099,13 @@ def test_insert(self): self.nb.insert('end', 0) self.assertEqual(self.nb.tabs(), tabs) # bad moves - self.assertRaises(tkinter.TclError, self.nb.insert, 2, tabs[0]) + if tk_version >= (8, 7): + self.nb.insert(2, tabs[0]) + self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0])) + self.nb.insert(2, tabs[1]) + self.assertEqual(self.nb.tabs(), tabs) + else: + self.assertRaises(tkinter.TclError, self.nb.insert, 2, tabs[0]) self.assertRaises(tkinter.TclError, self.nb.insert, -1, tabs[0]) # new tab @@ -1051,7 +1117,11 @@ def test_insert(self): self.nb.insert(self.child1, child3) self.assertEqual(self.nb.tabs(), (str(child3), ) + tabs) self.nb.forget(child3) - self.assertRaises(tkinter.TclError, self.nb.insert, 2, child3) + if tk_version >= (8, 7): + self.nb.insert(2, child3) + self.assertEqual(self.nb.tabs(), (*tabs, str(child3))) + else: + self.assertRaises(tkinter.TclError, self.nb.insert, 2, child3) self.assertRaises(tkinter.TclError, self.nb.insert, -1, child3) # bad inserts @@ -1333,7 +1403,8 @@ def test_configure_columns(self): self.checkParam(widget, 'columns', 'a b c', expected=('a', 'b', 'c')) self.checkParam(widget, 'columns', ('a', 'b', 'c')) - self.checkParam(widget, 'columns', '') + self.checkParam(widget, 'columns', '', + expected=() if tk_version >= (8, 7) else '') def test_configure_displaycolumns(self): widget = self.create() @@ -1346,10 +1417,13 @@ def test_configure_displaycolumns(self): self.checkParam(widget, 'displaycolumns', (2, 1, 0)) self.checkInvalidParam(widget, 'displaycolumns', ('a', 'b', 'd'), errmsg='Invalid column index d') + errmsg = ('Column index "{}" out of bounds' + if tk_version >= (8, 7) else + 'Column index {} out of bounds') self.checkInvalidParam(widget, 'displaycolumns', (1, 2, 3), - errmsg='Column index 3 out of bounds') + errmsg=errmsg.format(3)) self.checkInvalidParam(widget, 'displaycolumns', (1, -2), - errmsg='Column index -2 out of bounds') + errmsg=errmsg.format(-2)) def test_configure_height(self): widget = self.create() From fae9d8553cdb5ea9ba8ffd35b2ba7516db214eba Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2024 11:00:40 +0300 Subject: [PATCH 08/30] Fix test_configure_from and test_configure_to. --- Lib/test/test_tkinter/test_widgets.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index be552483ef4df0..41e186c6f25270 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -489,12 +489,12 @@ def test_configure_from(self): widget = self.create() self.checkParam(widget, 'to', 100.0) self.checkFloatParam(widget, 'from', -10, 10.2, 11.7) - if widget.info_patchlevel() < (8, 7): + if tk_version >= (8, 7): + self.checkFloatParam(widget, 'from', 200, expected=100) + else: self.checkInvalidParam( widget, 'from', 200, errmsg='-to value must be greater than -from value') - else: - self.checkFloatParam(widget, 'from', 100) def test_configure_increment(self): widget = self.create() @@ -504,12 +504,12 @@ def test_configure_to(self): widget = self.create() self.checkParam(widget, 'from', -100.0) self.checkFloatParam(widget, 'to', -10, 10.2, 11.7) - if widget.info_patchlevel() < (8, 7): + if tk_version >= (8, 7): + self.checkFloatParam(widget, 'to', -200, expected=-100) + else: self.checkInvalidParam( widget, 'to', -200, errmsg='-to value must be greater than -from value') - else: - self.checkFloatParam(widget, 'to', -100) def test_configure_values(self): # XXX From f6b26cf9373a0eba0af19e928fac364b1ad84eb1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2024 11:50:05 +0300 Subject: [PATCH 09/30] Polishing. --- Lib/test/test_tkinter/test_widgets.py | 13 ++++----- Lib/test/test_tkinter/widget_tests.py | 7 ++--- Lib/test/test_ttk/test_widgets.py | 38 +++++++++------------------ 3 files changed, 21 insertions(+), 37 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 41e186c6f25270..101744346ef979 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1428,14 +1428,11 @@ def test_configure_title(self): def test_configure_type(self): widget = self.create() - opts = ('normal, tearoff, or menubar' - if widget.info_patchlevel() < (8, 7) else - 'menubar, normal, or tearoff') - self.checkEnumParam( - widget, 'type', - 'normal', 'tearoff', 'menubar', - errmsg='bad type "{}": must be ' + opts, - ) + if tk_version >= (8, 7): + values = ('menubar', 'normal', 'tearoff') + else: + values = ('normal', 'tearoff', 'menubar') + self.checkEnumParam(widget, 'type', *values) def test_entryconfigure(self): m1 = self.create() diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index 0aed277af4cb60..c3b4bcea3806c1 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -126,9 +126,10 @@ def checkEnumParam(self, widget, name, *values, errmsg=None, **kwargs): name, ', '.join(values[:-1]), ',' if len(values) > 2 else '', - values[-1]) - self.checkInvalidParam(widget, name, '', - errmsg='ambiguous' + errmsg2) + values[-1] or '""') + if '' not in values: + self.checkInvalidParam(widget, name, '', + errmsg='ambiguous' + errmsg2) errmsg = 'bad' + errmsg2 self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 5a041e82da359d..2b48753816108a 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -57,6 +57,11 @@ def test_configure_style(self): self.assertEqual(widget2['class'], 'Foo') # XXX + def test_configure_relief(self): + widget = self.create() + self.checkReliefParam(widget, 'relief', + allow_empty=(tk_version >= (8, 7))) + def test_configure_underline(self): StandardOptionsTests.test_configure_underline(self, empty_value='') @@ -132,11 +137,6 @@ class FrameTest(AbstractToplevelTest, unittest.TestCase): def create(self, **kwargs): return ttk.Frame(self.root, **kwargs) - def test_configure_relief(self): - widget = self.create() - self.checkReliefParam(widget, 'relief', - allow_empty=(tk_version >= (8, 7))) - @add_standard_options(StandardTtkOptionsTests) class LabelFrameTest(AbstractToplevelTest, unittest.TestCase): @@ -163,11 +163,6 @@ def test_configure_labelwidget(self): self.checkParam(widget, 'labelwidget', label, expected='.foo') label.destroy() - def test_configure_relief(self): - widget = self.create() - self.checkReliefParam(widget, 'relief', - allow_empty=(tk_version >= (8, 7))) - class AbstractLabelTest(AbstractWidgetTest): @@ -185,15 +180,11 @@ def checkImageParam(self, widget, name): errmsg='image "spam" doesn\'t exist') def test_configure_compound(self): - options = 'none text image center top bottom left right'.split() + values = 'none text image center top bottom left right'.split() if tk_version >= (8, 7): - options.append('') - errmsg = ( - 'bad compound "{}": must be' - f' {", ".join(options[:-1])}, or {options[-1] or '""'}' - ) + values.append('') widget = self.create() - self.checkEnumParam(widget, 'compound', *options, errmsg=errmsg) + self.checkEnumParam(widget, 'compound', *values) def test_configure_state(self): widget = self.create() @@ -223,11 +214,6 @@ def test_configure_font(self): self.checkParam(widget, 'font', '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') - def test_configure_relief(self): - widget = self.create() - self.checkReliefParam(widget, 'relief', - allow_empty=(tk_version >= (8, 7))) - @add_standard_options(StandardTtkOptionsTests) class ButtonTest(AbstractLabelTest, unittest.TestCase): @@ -646,19 +632,19 @@ def test_add(self): self.assertRaises(tkinter.TclError, self.paned.pane, 2) good_child.destroy() other_child.destroy() - if tk_version < (8, 7): + if get_tk_patchlevel(self.root) != (8, 7, 0, 'beta', 1): # BUG: Crash in Tk 8.7b1 self.assertRaises(tkinter.TclError, self.paned.pane, 0) def test_forget(self): - if tk_version < (8, 7): + if get_tk_patchlevel(self.root) != (8, 7, 0, 'beta', 1): # BUG: Crash in Tk 8.7b1 self.assertRaises(tkinter.TclError, self.paned.forget, None) self.assertRaises(tkinter.TclError, self.paned.forget, 0) self.paned.add(ttk.Label(self.root)) self.paned.forget(0) - if tk_version < (8, 7): + if get_tk_patchlevel(self.root) != (8, 7, 0, 'beta', 1): # BUG: Crash in Tk 8.7b1 self.assertRaises(tkinter.TclError, self.paned.forget, 0) @@ -703,7 +689,7 @@ def test_insert(self): (str(child3), str(child2), str(child))) def test_pane(self): - if tk_version < (8, 7): + if get_tk_patchlevel(self.root) != (8, 7, 0, 'beta', 1): # BUG: Crash in Tk 8.7b1 self.assertRaises(tkinter.TclError, self.paned.pane, 0) From 9441f07c07a40b3c2c56e3766901af8a16e25560 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2024 12:01:10 +0300 Subject: [PATCH 10/30] Fix more tests. --- Lib/test/test_ttk/test_widgets.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 2b48753816108a..91703b87f31ed7 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -214,6 +214,11 @@ def test_configure_font(self): self.checkParam(widget, 'font', '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') + def test_keys(self): + if get_tk_patchlevel(self.root) == (8, 7, 0, 'beta', 1): + self.skipTest('Bug in Tk8.7b1') + super().test_keys() + @add_standard_options(StandardTtkOptionsTests) class ButtonTest(AbstractLabelTest, unittest.TestCase): @@ -285,7 +290,10 @@ def cb_test(): cbtn['command'] = '' res = cbtn.invoke() - self.assertFalse(str(res)) + if tk_version >= (8, 7): + self.assertFalse(res, ()) + else: + self.assertEqual(str(res), '') self.assertLessEqual(len(success), 1) self.assertEqual(cbtn['offvalue'], cbtn.tk.globalgetvar(cbtn['variable'])) @@ -523,7 +531,7 @@ def check_get_current(getval, currval): self.assertEqual(self.combo.get(), getval) self.assertEqual(self.combo.current(), currval) - self.assertEqual(self.combo['values'], '') + self.assertIn(self.combo['values'], ((), '')) check_get_current('', -1) self.checkParam(self.combo, 'values', 'mon tue wed thur', From 63d94800f88098a708befc223cae86053c8078b9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2024 12:13:56 +0300 Subject: [PATCH 11/30] Fix for wantobjects=0. --- Lib/test/test_ttk/test_widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 91703b87f31ed7..0472eef1c90421 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -777,7 +777,7 @@ def cb_test(): cbtn2['command'] = '' res = cbtn2.invoke() - if tk_version >= (8, 7): + if tk_version >= (8, 7) and self.wantobjects: self.assertEqual(res, ()) else: self.assertEqual(str(res), '') From dfebcde80237d35e922cf5d198f56fa6e0d8397d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2024 12:16:17 +0300 Subject: [PATCH 12/30] Update the NEWS entry. --- .../next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst b/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst index c0d396488e14eb..eb20d88aad7efb 100644 --- a/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst +++ b/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst @@ -1,3 +1 @@ -Where applicable update tkinter tests for 8.7 by adding '' to options in -error messages, testing '' for validity, and testing acceptance of 'to' -value < 'from' value in a spinbox (which switches the values). +Fix Tkinter tests for Tcl/Tk 8.7. From d30d55c359e8ac0ab2883b68082ed242d9fe8ef3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2024 14:37:49 +0300 Subject: [PATCH 13/30] Fix tests with Tcl/Tk 8.6. --- Lib/test/test_tkinter/test_widgets.py | 3 ++- Lib/test/test_tkinter/widget_tests.py | 5 +++-- Lib/test/test_ttk/test_widgets.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 101744346ef979..23b2366918ede5 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1432,7 +1432,8 @@ def test_configure_type(self): values = ('menubar', 'normal', 'tearoff') else: values = ('normal', 'tearoff', 'menubar') - self.checkEnumParam(widget, 'type', *values) + self.checkEnumParam(widget, 'type', *values, + allow_empty=tk_version < (8, 7)) def test_entryconfigure(self): m1 = self.create() diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index c3b4bcea3806c1..295557687962bb 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -119,7 +119,8 @@ def command(*args): self.assertTrue(widget[name]) self.checkParams(widget, name, '') - def checkEnumParam(self, widget, name, *values, errmsg=None, **kwargs): + def checkEnumParam(self, widget, name, *values, + errmsg=None, allow_empty=False, **kwargs): self.checkParams(widget, name, *values, **kwargs) if errmsg is None: errmsg2 = ' %s "{}": must be %s%s or %s' % ( @@ -127,7 +128,7 @@ def checkEnumParam(self, widget, name, *values, errmsg=None, **kwargs): ', '.join(values[:-1]), ',' if len(values) > 2 else '', values[-1] or '""') - if '' not in values: + if '' not in values and not allow_empty: self.checkInvalidParam(widget, name, '', errmsg='ambiguous' + errmsg2) errmsg = 'bad' + errmsg2 diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 0472eef1c90421..9f117db767b83d 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -184,7 +184,7 @@ def test_configure_compound(self): if tk_version >= (8, 7): values.append('') widget = self.create() - self.checkEnumParam(widget, 'compound', *values) + self.checkEnumParam(widget, 'compound', *values, allow_empty=True) def test_configure_state(self): widget = self.create() From d18b84190899a3a7a0eb8ac8a002935e57361679 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 4 Jun 2024 13:59:43 +0300 Subject: [PATCH 14/30] Fix tests for newer Tk 8.7. --- .../test_tkinter/test_geometry_managers.py | 33 ++++++++---- Lib/test/test_tkinter/test_widgets.py | 33 +++++++++--- Lib/test/test_tkinter/widget_tests.py | 30 +++++------ Lib/test/test_ttk/test_widgets.py | 52 +++++++------------ 4 files changed, 82 insertions(+), 66 deletions(-) diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index 92951de8f4e697..e2a3301391cfe5 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -10,6 +10,9 @@ requires('gui') +EXPECTED_SCREEN_DISTANCE_ERRMSG = '(bad|expected) screen distance (but got )?"{}"' +EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG = '(bad|expected) screen distance (or "" but got )?"{}"' + class PackTest(AbstractWidgetTest, unittest.TestCase): test_keys = None @@ -317,7 +320,8 @@ def test_place_configure_x(self): self.assertEqual(f2.place_info()['x'], '-10') self.root.update() self.assertEqual(f2.winfo_x(), 190) - with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('spam')): f2.place_configure(in_=f, x='spam') def test_place_configure_y(self): @@ -334,7 +338,8 @@ def test_place_configure_y(self): self.assertEqual(f2.place_info()['y'], '-10') self.root.update() self.assertEqual(f2.winfo_y(), 110) - with self.assertRaisesRegex(TclError, 'bad screen distance "spam"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('spam')): f2.place_configure(in_=f, y='spam') def test_place_configure_relx(self): @@ -391,7 +396,8 @@ def test_place_configure_width(self): f2.place_configure(width='') self.root.update() self.assertEqual(f2.winfo_width(), 30) - with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('abcd')): f2.place_configure(width='abcd') def test_place_configure_height(self): @@ -402,7 +408,8 @@ def test_place_configure_height(self): f2.place_configure(height='') self.root.update() self.assertEqual(f2.winfo_height(), 60) - with self.assertRaisesRegex(TclError, 'bad screen distance "abcd"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('abcd')): f2.place_configure(height='abcd') def test_place_configure_relwidth(self): @@ -629,7 +636,8 @@ def test_grid_columnconfigure(self): self.assertEqual(self.root.grid_columnconfigure(0, 'weight'), 4) def test_grid_columnconfigure_minsize(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('foo')): self.root.grid_columnconfigure(0, minsize='foo') self.root.grid_columnconfigure(0, minsize=10) self.assertEqual(self.root.grid_columnconfigure(0, 'minsize'), 10) @@ -646,7 +654,8 @@ def test_grid_columnconfigure_weight(self): self.assertEqual(self.root.grid_columnconfigure(0)['weight'], 3) def test_grid_columnconfigure_pad(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('foo')): self.root.grid_columnconfigure(0, pad='foo') with self.assertRaisesRegex(TclError, 'invalid arg "-pad": ' 'should be non-negative'): @@ -683,7 +692,8 @@ def test_grid_rowconfigure(self): self.assertEqual(self.root.grid_rowconfigure(0, 'weight'), 4) def test_grid_rowconfigure_minsize(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('foo')): self.root.grid_rowconfigure(0, minsize='foo') self.root.grid_rowconfigure(0, minsize=10) self.assertEqual(self.root.grid_rowconfigure(0, 'minsize'), 10) @@ -700,7 +710,8 @@ def test_grid_rowconfigure_weight(self): self.assertEqual(self.root.grid_rowconfigure(0)['weight'], 3) def test_grid_rowconfigure_pad(self): - with self.assertRaisesRegex(TclError, 'bad screen distance "foo"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('foo')): self.root.grid_rowconfigure(0, pad='foo') with self.assertRaisesRegex(TclError, 'invalid arg "-pad": ' 'should be non-negative'): @@ -818,9 +829,11 @@ def test_grid_location(self): self.root.grid_location(0) with self.assertRaises(TypeError): self.root.grid_location(0, 0, 0) - with self.assertRaisesRegex(TclError, 'bad screen distance "x"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('x')): self.root.grid_location('x', 'y') - with self.assertRaisesRegex(TclError, 'bad screen distance "y"'): + with self.assertRaisesRegex(TclError, + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('y')): self.root.grid_location('1c', 'y') t = self.root # de-maximize diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 23b2366918ede5..bf0632ac46e62b 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -14,6 +14,9 @@ requires('gui') +EXPECTED_SCREEN_DISTANCE_ERRMSG = '(bad|expected) screen distance (but got )?"{}"' +EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG = '(bad|expected) screen distance (or "" but got )?"{}"' + def float_round(x): return float(round(x)) @@ -674,7 +677,7 @@ def test_configure_tabs(self): self.checkParam(widget, 'tabs', '2c left 4c 6c center', expected=('2c', 'left', '4c', '6c', 'center')) self.checkInvalidParam(widget, 'tabs', 'spam', - errmsg='bad screen distance "spam"') + errmsg=EXPECTED_SCREEN_DISTANCE_ERRMSG.format('spam')) def test_configure_tabstyle(self): widget = self.create() @@ -1343,7 +1346,7 @@ def test_paneconfigure_height(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'height', 10, 10) self.check_paneconfigure_bad(p, b, 'height', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue')) def test_paneconfigure_hide(self): p, b, c = self.create2() @@ -1355,19 +1358,19 @@ def test_paneconfigure_minsize(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'minsize', 10, 10) self.check_paneconfigure_bad(p, b, 'minsize', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_padx(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'padx', 1.3, 1) self.check_paneconfigure_bad(p, b, 'padx', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_pady(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'pady', 1.3, 1) self.check_paneconfigure_bad(p, b, 'pady', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_sticky(self): p, b, c = self.create2() @@ -1388,7 +1391,7 @@ def test_paneconfigure_width(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'width', 10, 10) self.check_paneconfigure_bad(p, b, 'width', - 'bad screen distance "badValue"') + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue')) @add_standard_options(StandardOptionsTests) @@ -1479,6 +1482,8 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase): 'takefocus', 'text', 'textvariable', 'width', ) _conv_pad_pixels = False + if tk_version >= (8, 7): + _conv_pixels = False def create(self, **kwargs): return tkinter.Message(self.root, **kwargs) @@ -1487,6 +1492,22 @@ def test_configure_aspect(self): widget = self.create() self.checkIntegerParam(widget, 'aspect', 250, 0, -300) + def test_configure_highlightthickness(self): + widget = self.create() + self.checkPixelsParam(widget, 'highlightthickness', + 0, 1.3, 2.6, 6, '10p') + expected = -2 if tk_version >= (8, 7) else 0 + self.checkParam(widget, 'highlightthickness', -2, expected=expected, + conv=self._conv_pad_pixels) + + def test_configure_padx(self): + widget = self.create() + self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m', + conv=self._conv_pad_pixels) + expected = '' if tk_version >= (8, 7) else -2 + self.checkParam(widget, 'padx', -2, expected=expected, + conv=self._conv_pad_pixels) + class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index 295557687962bb..eff0c07a1fdd04 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -1,5 +1,6 @@ # Common tests for test_tkinter/test_widgets.py and test_ttk/test_widgets.py +import re import tkinter from test.test_tkinter.support import (AbstractTkTest, tk_version, pixels_conv, tcl_obj_eq) @@ -56,16 +57,12 @@ def checkParam(self, widget, name, value, *, expected=_sentinel, def checkInvalidParam(self, widget, name, value, errmsg=None): orig = widget[name] if errmsg is not None: - errmsg = errmsg.format(value) - with self.assertRaises(tkinter.TclError) as cm: + errmsg = errmsg.format(re.escape(str(value))) + with self.assertRaisesRegex(tkinter.TclError, errmsg or ''): widget[name] = value - if errmsg is not None: - self.assertEqual(str(cm.exception), errmsg) self.assertEqual(widget[name], orig) - with self.assertRaises(tkinter.TclError) as cm: + with self.assertRaisesRegex(tkinter.TclError, errmsg or ''): widget.configure({name: value}) - if errmsg is not None: - self.assertEqual(str(cm.exception), errmsg) self.assertEqual(widget[name], orig) def checkParams(self, widget, name, *values, **kwargs): @@ -120,11 +117,12 @@ def command(*args): self.checkParams(widget, name, '') def checkEnumParam(self, widget, name, *values, - errmsg=None, allow_empty=False, **kwargs): + errmsg=None, allow_empty=False, fullname=None, + **kwargs): self.checkParams(widget, name, *values, **kwargs) if errmsg is None: errmsg2 = ' %s "{}": must be %s%s or %s' % ( - name, + fullname or name, ', '.join(values[:-1]), ',' if len(values) > 2 else '', values[-1] or '""') @@ -148,9 +146,9 @@ def checkPixelsParam(self, widget, name, *values, self.checkParam(widget, name, value, expected=expected, conv=conv1, **kwargs) self.checkInvalidParam(widget, name, '6x', - errmsg='bad screen distance "6x"') + errmsg='(bad|expected) screen distance ((or "" )?but got )?"6x"') self.checkInvalidParam(widget, name, 'spam', - errmsg='bad screen distance "spam"') + errmsg='(bad|expected) screen distance ((or "" )?but got )?"spam"') def checkReliefParam(self, widget, name, *, allow_empty=False): options = ['flat', 'groove', 'raised', 'ridge', 'solid', 'sunken'] @@ -347,11 +345,7 @@ def test_configure_jump(self): def test_configure_justify(self): widget = self.create() self.checkEnumParam(widget, 'justify', 'left', 'right', 'center', - errmsg='bad justification "{}": must be ' - 'left, right, or center') - self.checkInvalidParam(widget, 'justify', '', - errmsg='ambiguous justification "": must be ' - 'left, right, or center') + fullname='justification') def test_configure_orient(self): widget = self.create() @@ -422,8 +416,8 @@ def test_configure_underline(self, *, empty_value=-1): if tk_version >= (8, 7): self.checkParams(widget, 'underline', 0, 1, 10) self.checkParam(widget, 'underline', '', expected=empty_value) - errmsg = ('bad index "{}": must be integer?[+-]integer?, ' - 'end?[+-]integer?, or ""') + errmsg = (r'bad index "{}": must be integer\?\[\+-\]integer\?, ' + r'end\?\[\+-\]integer\?, or ""') self.checkInvalidParam(widget, 'underline', '10p', errmsg=errmsg) self.checkInvalidParam(widget, 'underline', 3.2, errmsg=errmsg) else: diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 9f117db767b83d..acc9188294449c 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -214,11 +214,13 @@ def test_configure_font(self): self.checkParam(widget, 'font', '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') - def test_keys(self): - if get_tk_patchlevel(self.root) == (8, 7, 0, 'beta', 1): - self.skipTest('Bug in Tk8.7b1') - super().test_keys() - + def test_configure_justify(self): + widget = self.create() + values = ('left', 'right', 'center') + if tk_version >= (8, 7): + values += ('',) + self.checkEnumParam(widget, 'justify', *values, + fullname='justification') @add_standard_options(StandardTtkOptionsTests) class ButtonTest(AbstractLabelTest, unittest.TestCase): @@ -634,27 +636,18 @@ def test_add(self): other_child = ttk.Label(self.paned) self.paned.add(other_child) self.assertEqual(self.paned.pane(0), self.paned.pane(1)) - if tk_version >= (8, 7): - self.assertEqual(self.paned.pane(2), self.paned.pane(1)) - else: - self.assertRaises(tkinter.TclError, self.paned.pane, 2) + self.assertRaises(tkinter.TclError, self.paned.pane, 2) good_child.destroy() other_child.destroy() - if get_tk_patchlevel(self.root) != (8, 7, 0, 'beta', 1): - # BUG: Crash in Tk 8.7b1 - self.assertRaises(tkinter.TclError, self.paned.pane, 0) + self.assertRaises(tkinter.TclError, self.paned.pane, 0) def test_forget(self): - if get_tk_patchlevel(self.root) != (8, 7, 0, 'beta', 1): - # BUG: Crash in Tk 8.7b1 - self.assertRaises(tkinter.TclError, self.paned.forget, None) - self.assertRaises(tkinter.TclError, self.paned.forget, 0) + self.assertRaises(tkinter.TclError, self.paned.forget, None) + self.assertRaises(tkinter.TclError, self.paned.forget, 0) self.paned.add(ttk.Label(self.root)) self.paned.forget(0) - if get_tk_patchlevel(self.root) != (8, 7, 0, 'beta', 1): - # BUG: Crash in Tk 8.7b1 - self.assertRaises(tkinter.TclError, self.paned.forget, 0) + self.assertRaises(tkinter.TclError, self.paned.forget, 0) def test_insert(self): self.assertRaises(tkinter.TclError, self.paned.insert, None, 0) @@ -697,9 +690,7 @@ def test_insert(self): (str(child3), str(child2), str(child))) def test_pane(self): - if get_tk_patchlevel(self.root) != (8, 7, 0, 'beta', 1): - # BUG: Crash in Tk 8.7b1 - self.assertRaises(tkinter.TclError, self.paned.pane, 0) + self.assertRaises(tkinter.TclError, self.paned.pane, 0) child = ttk.Label(self.root) self.paned.add(child) @@ -800,10 +791,13 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase): def create(self, **kwargs): return ttk.Menubutton(self.root, **kwargs) - def test_direction(self): + def test_configure_direction(self): widget = self.create() - self.checkEnumParam(widget, 'direction', - 'above', 'below', 'left', 'right', 'flush') + if tk_version >= (8, 7): + values = 'above', 'below', 'flush', 'left', 'right' + else: + values = 'above', 'below', 'left', 'right', 'flush' + self.checkEnumParam(widget, 'direction', *values) def test_configure_menu(self): widget = self.create() @@ -1093,13 +1087,7 @@ def test_insert(self): self.nb.insert('end', 0) self.assertEqual(self.nb.tabs(), tabs) # bad moves - if tk_version >= (8, 7): - self.nb.insert(2, tabs[0]) - self.assertEqual(self.nb.tabs(), (tabs[1], tabs[0])) - self.nb.insert(2, tabs[1]) - self.assertEqual(self.nb.tabs(), tabs) - else: - self.assertRaises(tkinter.TclError, self.nb.insert, 2, tabs[0]) + self.assertRaises(tkinter.TclError, self.nb.insert, 2, tabs[0]) self.assertRaises(tkinter.TclError, self.nb.insert, -1, tabs[0]) # new tab From 93ffd333131e1f1d629ec7453db4382dc19d2d92 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 4 Jun 2024 21:19:53 +0300 Subject: [PATCH 15/30] Fix tests on Tcl/Tk 9.0. --- Lib/test/test_tcl.py | 10 +++++++++- Lib/test/test_tkinter/test_variables.py | 4 +++- Lib/test/test_tkinter/widget_tests.py | 2 +- Lib/test/test_ttk/test_widgets.py | 5 +---- Lib/tkinter/ttk.py | 9 ++++++--- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index 553d54329d7939..e6cf2c7ace0617 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -219,10 +219,18 @@ def test_evalfile_surrogates_in_result(self): with open(filename, 'wb') as f: f.write(b""" set a "<\xed\xa0\xbd\xed\xb2\xbb>" + """) + if tcl_version >= (9, 0): + self.assertRaises(TclError, tcl.evalfile, filename) + else: + tcl.evalfile(filename) + self.assertEqual(tcl.eval('set a'), '<\U0001f4bb>') + + with open(filename, 'wb') as f: + f.write(b""" set b "<\\ud83d\\udcbb>" """) tcl.evalfile(filename) - self.assertEqual(tcl.eval('set a'), '<\U0001f4bb>') self.assertEqual(tcl.eval('set b'), '<\U0001f4bb>') def testEvalFileException(self): diff --git a/Lib/test/test_tkinter/test_variables.py b/Lib/test/test_tkinter/test_variables.py index c1d232e2febc7a..def7aec077e800 100644 --- a/Lib/test/test_tkinter/test_variables.py +++ b/Lib/test/test_tkinter/test_variables.py @@ -6,7 +6,7 @@ from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl, TclError) from test.support import ALWAYS_EQ -from test.test_tkinter.support import AbstractDefaultRootTest +from test.test_tkinter.support import AbstractDefaultRootTest, tcl_version class Var(Variable): @@ -112,6 +112,8 @@ def test_initialize(self): self.assertTrue(v.side_effect) def test_trace_old(self): + if tcl_version >= (9, 0): + self.skipTest('requires Tcl version < 9.0') # Old interface v = Variable(self.root) vname = str(v) diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index eff0c07a1fdd04..f960a0c69fc77c 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -411,7 +411,7 @@ def test_configure_troughcolor(self): widget = self.create() self.checkColorParam(widget, 'troughcolor') - def test_configure_underline(self, *, empty_value=-1): + def test_configure_underline(self, *, empty_value=''): widget = self.create() if tk_version >= (8, 7): self.checkParams(widget, 'underline', 0, 1, 10) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index acc9188294449c..4c4131d352dc26 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -62,9 +62,6 @@ def test_configure_relief(self): self.checkReliefParam(widget, 'relief', allow_empty=(tk_version >= (8, 7))) - def test_configure_underline(self): - StandardOptionsTests.test_configure_underline(self, empty_value='') - class WidgetTest(AbstractTkTest, unittest.TestCase): """Tests methods available in every ttk widget.""" @@ -1398,7 +1395,7 @@ def test_configure_displaycolumns(self): expected=('#all',)) self.checkParam(widget, 'displaycolumns', (2, 1, 0)) self.checkInvalidParam(widget, 'displaycolumns', ('a', 'b', 'd'), - errmsg='Invalid column index d') + errmsg='Invalid column index "?d"?') errmsg = ('Column index "{}" out of bounds' if tk_version >= (8, 7) else 'Column index {} out of bounds') diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index 5ca938a670831a..073b3ae20797c3 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -690,7 +690,10 @@ def current(self, newindex=None): returns the index of the current value in the list of values or -1 if the current value does not appear in the list.""" if newindex is None: - return self.tk.getint(self.tk.call(self._w, "current")) + res = self.tk.call(self._w, "current") + if res == '': + return -1 + return self.tk.getint(res) return self.tk.call(self._w, "current", newindex) @@ -1522,7 +1525,7 @@ def __init__(self, master=None, variable=None, from_=0, to=10, **kw): self.label.place(anchor='n' if label_side == 'top' else 's') # update the label as scale or variable changes - self.__tracecb = self._variable.trace_variable('w', self._adjust) + self.__tracecb = self._variable.trace_add('write', self._adjust) self.bind('', self._adjust) self.bind('', self._adjust) @@ -1530,7 +1533,7 @@ def __init__(self, master=None, variable=None, from_=0, to=10, **kw): def destroy(self): """Destroy this widget and possibly its associated variable.""" try: - self._variable.trace_vdelete('w', self.__tracecb) + self._variable.trace_remove('write', self.__tracecb) except AttributeError: pass else: From 8f18aca61b52ac455c922cd09495fbf02b36a821 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 4 Jun 2024 21:32:59 +0300 Subject: [PATCH 16/30] Fix tests on Tcl/Tk 8.7. --- Lib/test/test_tkinter/test_widgets.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index bf0632ac46e62b..a132f1d4431fc0 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -150,6 +150,10 @@ def test_configure_highlightthickness(self): self.checkPixelsParam(widget, 'highlightthickness', 0, 1.3, 2.6, 6, -2, '10p') + if tk_version == (8, 7): + def test_configure_underline(self): + StandardOptionsTests.test_configure_underline(self, empty_value=-1) + @add_standard_options(StandardOptionsTests) class LabelTest(AbstractLabelTest, unittest.TestCase): From f6ce7184f4967cbb1968ece35279d689fd0b2b09 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 4 Jun 2024 21:53:05 +0300 Subject: [PATCH 17/30] Simplify test code. --- Lib/test/test_tkinter/widget_tests.py | 27 +++++++++++---------------- Lib/test/test_ttk/test_widgets.py | 4 +--- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index f960a0c69fc77c..ab3d1478179e0e 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -71,29 +71,26 @@ def checkParams(self, widget, name, *values, **kwargs): def checkIntegerParam(self, widget, name, *values, **kwargs): self.checkParams(widget, name, *values, **kwargs) - self.checkInvalidParam(widget, name, '', - errmsg='expected integer but got ""') errmsg = 'expected integer but got "{}"' + self.checkInvalidParam(widget, name, '', errmsg=errmsg) self.checkInvalidParam(widget, name, '10p', errmsg=errmsg) self.checkInvalidParam(widget, name, 3.2, errmsg=errmsg) def checkFloatParam(self, widget, name, *values, conv=float, **kwargs): for value in values: self.checkParam(widget, name, value, conv=conv, **kwargs) - self.checkInvalidParam(widget, name, '', - errmsg='expected floating-point number but got ""') - self.checkInvalidParam(widget, name, 'spam', - errmsg='expected floating-point number but got "spam"') + errmsg = 'expected floating-point number but got "{}"' + self.checkInvalidParam(widget, name, '', errmsg=errmsg) + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkBooleanParam(self, widget, name): for value in (False, 0, 'false', 'no', 'off'): self.checkParam(widget, name, value, expected=0) for value in (True, 1, 'true', 'yes', 'on'): self.checkParam(widget, name, value, expected=1) - self.checkInvalidParam(widget, name, '', - errmsg='expected boolean value but got ""') - self.checkInvalidParam(widget, name, 'spam', - errmsg='expected boolean value but got "spam"') + errmsg='expected boolean value but got "{}"' + self.checkInvalidParam(widget, name, '', errmsg=errmsg) + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkColorParam(self, widget, name, *, allow_empty=None, **kwargs): self.checkParams(widget, name, @@ -145,10 +142,9 @@ def checkPixelsParam(self, widget, name, *values, conv1 = round self.checkParam(widget, name, value, expected=expected, conv=conv1, **kwargs) - self.checkInvalidParam(widget, name, '6x', - errmsg='(bad|expected) screen distance ((or "" )?but got )?"6x"') - self.checkInvalidParam(widget, name, 'spam', - errmsg='(bad|expected) screen distance ((or "" )?but got )?"spam"') + errmsg = '(bad|expected) screen distance ((or "" )?but got )?"{}"' + self.checkInvalidParam(widget, name, '6x', errmsg=errmsg) + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkReliefParam(self, widget, name, *, allow_empty=False): options = ['flat', 'groove', 'raised', 'ridge', 'solid', 'sunken'] @@ -160,8 +156,7 @@ def checkReliefParam(self, widget, name, *, allow_empty=False): errmsg = f'bad relief "spam": must be {opstring}, or {lastop or '""'}' if tk_version < (8, 6): errmsg = None - self.checkInvalidParam(widget, name, 'spam', - errmsg=errmsg) + self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkImageParam(self, widget, name): image = tkinter.PhotoImage(master=self.root, name='image1') diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 4c4131d352dc26..c33a29187c0935 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -1396,9 +1396,7 @@ def test_configure_displaycolumns(self): self.checkParam(widget, 'displaycolumns', (2, 1, 0)) self.checkInvalidParam(widget, 'displaycolumns', ('a', 'b', 'd'), errmsg='Invalid column index "?d"?') - errmsg = ('Column index "{}" out of bounds' - if tk_version >= (8, 7) else - 'Column index {} out of bounds') + errmsg = 'Column index "?{}"? out of bounds' self.checkInvalidParam(widget, 'displaycolumns', (1, 2, 3), errmsg=errmsg.format(3)) self.checkInvalidParam(widget, 'displaycolumns', (1, -2), From 55a96fc7014b3f20a93e3046668641812dcdbd3a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 4 Jun 2024 22:00:45 +0300 Subject: [PATCH 18/30] Update NEWS. --- .../next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst b/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst index eb20d88aad7efb..63e5facb5cac2b 100644 --- a/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst +++ b/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst @@ -1 +1 @@ -Fix Tkinter tests for Tcl/Tk 8.7. +Fix Tkinter tests for Tcl/Tk 8.7 and 9.0. From 10baa244d72a3b0dd512ade728c1ee651c7a7e1b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 4 Jun 2024 22:02:11 +0300 Subject: [PATCH 19/30] Remove the NEWS entry. --- .../next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst diff --git a/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst b/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst deleted file mode 100644 index 63e5facb5cac2b..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-05-28-21-12-44.gh-issue-104855.viuQsR.rst +++ /dev/null @@ -1 +0,0 @@ -Fix Tkinter tests for Tcl/Tk 8.7 and 9.0. From f7843608c431d1f5a049471f89d6692e1b21886d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 5 Jun 2024 17:41:50 +0300 Subject: [PATCH 20/30] Polishing. --- Lib/test/test_tkinter/test_widgets.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index a132f1d4431fc0..e4fa7317bf34c1 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -876,28 +876,26 @@ def test_create_line(self): def test_create_polygon(self): c = self.create() tk87 = tk_version >= (8, 7) - i1 = c.create_polygon(20, 30, 40, 50, 60, 10) + # In Tk < 8.7 polygons are filled, but has no outline by default. + # This affects its size, so always explicitly specify outline. + i1 = c.create_polygon(20, 30, 40, 50, 60, 10, outline='red') self.assertEqual(c.coords(i1), [20.0, 30.0, 40.0, 50.0, 60.0, 10.0]) - self.assertEqual(c.bbox(i1), - (18, 8, 62, 52) if tk87 else (19, 9, 61, 51)) + self.assertEqual(c.bbox(i1), (18, 8, 62, 52)) self.assertEqual(c.itemcget(i1, 'joinstyle'), 'round') self.assertEqual(c.itemcget(i1, 'smooth'), '0') self.assertEqual(c.itemcget(i1, 'splinestep'), '12') - i2 = c.create_polygon([21, 31, 41, 51, 61, 11]) + i2 = c.create_polygon([21, 31, 41, 51, 61, 11], outline='red') self.assertEqual(c.coords(i2), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) - self.assertEqual(c.bbox(i2), - (19, 9, 63, 53) if tk87 else (20, 10, 62, 52)) + self.assertEqual(c.bbox(i2), (19, 9, 63, 53)) - i3 = c.create_polygon((22, 32), (42, 52), (62, 12)) + i3 = c.create_polygon((22, 32), (42, 52), (62, 12), outline='red') self.assertEqual(c.coords(i3), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) - self.assertEqual(c.bbox(i3), - (20, 10, 64, 54) if tk87 else (21, 11, 63, 53)) + self.assertEqual(c.bbox(i3), (20, 10, 64, 54)) - i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)]) + i4 = c.create_polygon([(23, 33), (43, 53), (63, 13)], outline='red') self.assertEqual(c.coords(i4), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) - self.assertEqual(c.bbox(i4), - (21, 11, 65, 55) if tk87 else (22, 12, 64, 54)) + self.assertEqual(c.bbox(i4), (21, 11, 65, 55)) self.assertRaises(TclError, c.create_polygon, 20, 30, 60) self.assertRaises(TclError, c.create_polygon, [20, 30, 60]) From b72910f5c30bc5bfa3e96186957bd1f8e6d96e59 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 5 Jun 2024 20:28:10 +0300 Subject: [PATCH 21/30] Refactor test_configure_underline. --- Lib/test/test_tkinter/test_widgets.py | 16 ++++++---------- Lib/test/test_tkinter/widget_tests.py | 22 ++++++++++++++++------ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index e4fa7317bf34c1..e4e7ff3ce4a57c 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -150,10 +150,6 @@ def test_configure_highlightthickness(self): self.checkPixelsParam(widget, 'highlightthickness', 0, 1.3, 2.6, 6, -2, '10p') - if tk_version == (8, 7): - def test_configure_underline(self): - StandardOptionsTests.test_configure_underline(self, empty_value=-1) - @add_standard_options(StandardOptionsTests) class LabelTest(AbstractLabelTest, unittest.TestCase): @@ -681,7 +677,7 @@ def test_configure_tabs(self): self.checkParam(widget, 'tabs', '2c left 4c 6c center', expected=('2c', 'left', '4c', '6c', 'center')) self.checkInvalidParam(widget, 'tabs', 'spam', - errmsg=EXPECTED_SCREEN_DISTANCE_ERRMSG.format('spam')) + errmsg=EXPECTED_SCREEN_DISTANCE_ERRMSG.format('spam')) def test_configure_tabstyle(self): widget = self.create() @@ -1348,7 +1344,7 @@ def test_paneconfigure_height(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'height', 10, 10) self.check_paneconfigure_bad(p, b, 'height', - EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue')) + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue')) def test_paneconfigure_hide(self): p, b, c = self.create2() @@ -1360,19 +1356,19 @@ def test_paneconfigure_minsize(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'minsize', 10, 10) self.check_paneconfigure_bad(p, b, 'minsize', - EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_padx(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'padx', 1.3, 1) self.check_paneconfigure_bad(p, b, 'padx', - EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_pady(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'pady', 1.3, 1) self.check_paneconfigure_bad(p, b, 'pady', - EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('badValue')) def test_paneconfigure_sticky(self): p, b, c = self.create2() @@ -1393,7 +1389,7 @@ def test_paneconfigure_width(self): p, b, c = self.create2() self.check_paneconfigure(p, b, 'width', 10, 10) self.check_paneconfigure_bad(p, b, 'width', - EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue')) + EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('badValue')) @add_standard_options(StandardOptionsTests) diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index ab3d1478179e0e..1b592cbfd86600 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -406,17 +406,27 @@ def test_configure_troughcolor(self): widget = self.create() self.checkColorParam(widget, 'troughcolor') - def test_configure_underline(self, *, empty_value=''): + def test_configure_underline(self): widget = self.create() + self.checkParams(widget, 'underline', 0, 1, 10) if tk_version >= (8, 7): - self.checkParams(widget, 'underline', 0, 1, 10) - self.checkParam(widget, 'underline', '', expected=empty_value) + is_ttk = widget.__class__.__module__ == 'tkinter.ttk' + default = -1 if tk_version == (8, 7) else '' + self.checkParam(widget, 'underline', '', + expected='' if is_ttk else default) + self.checkParam(widget, 'underline', '5+2', + expected='5+2' if is_ttk else 7) + self.checkParam(widget, 'underline', '5-2', + expected='5-2' if is_ttk else 3) + self.checkParam(widget, 'underline', 'end', expected='end') + self.checkParam(widget, 'underline', 'end-2', expected='end-2') errmsg = (r'bad index "{}": must be integer\?\[\+-\]integer\?, ' r'end\?\[\+-\]integer\?, or ""') - self.checkInvalidParam(widget, 'underline', '10p', errmsg=errmsg) - self.checkInvalidParam(widget, 'underline', 3.2, errmsg=errmsg) else: - self.checkIntegerParam(widget, 'underline', 0, 1, 10) + errmsg = 'expected integer but got "{}"' + self.checkInvalidParam(widget, 'underline', '', errmsg=errmsg) + self.checkInvalidParam(widget, 'underline', '10p', errmsg=errmsg) + self.checkInvalidParam(widget, 'underline', 3.2, errmsg=errmsg) def test_configure_wraplength(self): widget = self.create() From bfd47d109cd28e2d53ed69fa158b2cde8fa322db Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 6 Jun 2024 14:24:08 +0300 Subject: [PATCH 22/30] Remove special test_configure_padx for the message widget. --- Lib/test/test_tkinter/test_widgets.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index e4e7ff3ce4a57c..6e1bdb45c3a677 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1498,14 +1498,6 @@ def test_configure_highlightthickness(self): self.checkParam(widget, 'highlightthickness', -2, expected=expected, conv=self._conv_pad_pixels) - def test_configure_padx(self): - widget = self.create() - self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m', - conv=self._conv_pad_pixels) - expected = '' if tk_version >= (8, 7) else -2 - self.checkParam(widget, 'padx', -2, expected=expected, - conv=self._conv_pad_pixels) - class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): From 289c4ae59f8ba0db74116ff43e8a8aaeea8d7b39 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 6 Jun 2024 18:40:27 +0300 Subject: [PATCH 23/30] Refactor test_configure_highlightthickness. --- Lib/test/test_tkinter/test_widgets.py | 19 +++---------------- Lib/test/test_tkinter/widget_tests.py | 4 +++- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 6e1bdb45c3a677..34faeb0302c062 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -144,11 +144,7 @@ def test_configure_labelwidget(self): class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests): _conv_pixels = False - - def test_configure_highlightthickness(self): - widget = self.create() - self.checkPixelsParam(widget, 'highlightthickness', - 0, 1.3, 2.6, 6, -2, '10p') + clip_highlightthickness = False @add_standard_options(StandardOptionsTests) @@ -280,6 +276,7 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase): 'underline', 'width', 'wraplength', ) _conv_pixels = round + clip_highlightthickness = True def create(self, **kwargs): return tkinter.Menubutton(self.root, **kwargs) @@ -293,9 +290,6 @@ def test_configure_height(self): widget = self.create() self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str) - test_configure_highlightthickness = \ - StandardOptionsTests.test_configure_highlightthickness - def test_configure_image(self): widget = self.create() image = tkinter.PhotoImage(master=self.root, name='image1') @@ -1482,6 +1476,7 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase): _conv_pad_pixels = False if tk_version >= (8, 7): _conv_pixels = False + clip_highlightthickness = False def create(self, **kwargs): return tkinter.Message(self.root, **kwargs) @@ -1490,14 +1485,6 @@ def test_configure_aspect(self): widget = self.create() self.checkIntegerParam(widget, 'aspect', 250, 0, -300) - def test_configure_highlightthickness(self): - widget = self.create() - self.checkPixelsParam(widget, 'highlightthickness', - 0, 1.3, 2.6, 6, '10p') - expected = -2 if tk_version >= (8, 7) else 0 - self.checkParam(widget, 'highlightthickness', -2, expected=expected, - conv=self._conv_pad_pixels) - class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index 1b592cbfd86600..f706027cd49cae 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -13,6 +13,7 @@ class AbstractWidgetTest(AbstractTkTest): _conv_pixels = round _conv_pad_pixels = None _stringify = False + clip_highlightthickness = True @property def scaling(self): @@ -305,7 +306,8 @@ def test_configure_highlightthickness(self): widget = self.create() self.checkPixelsParam(widget, 'highlightthickness', 0, 1.3, 2.6, 6, '10p') - self.checkParam(widget, 'highlightthickness', -2, expected=0, + expected = 0 if self.clip_highlightthickness else -2 + self.checkParam(widget, 'highlightthickness', -2, expected=expected, conv=self._conv_pixels) def test_configure_image(self): From 19232e78cb85b0f740335ff8fe28c24e950fe9c2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 6 Jun 2024 19:27:20 +0300 Subject: [PATCH 24/30] Polishing. --- Lib/test/test_tkinter/widget_tests.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index f706027cd49cae..5f7fc3d5485d0a 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -89,7 +89,7 @@ def checkBooleanParam(self, widget, name): self.checkParam(widget, name, value, expected=0) for value in (True, 1, 'true', 'yes', 'on'): self.checkParam(widget, name, value, expected=1) - errmsg='expected boolean value but got "{}"' + errmsg = 'expected boolean value but got "{}"' self.checkInvalidParam(widget, name, '', errmsg=errmsg) self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) @@ -148,13 +148,13 @@ def checkPixelsParam(self, widget, name, *values, self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkReliefParam(self, widget, name, *, allow_empty=False): - options = ['flat', 'groove', 'raised', 'ridge', 'solid', 'sunken'] + values = ['flat', 'groove', 'raised', 'ridge', 'solid', 'sunken'] if allow_empty: - options.append('') - self.checkParams(widget, name, *options) - lastop = options.pop() - opstring = ', '.join(options) - errmsg = f'bad relief "spam": must be {opstring}, or {lastop or '""'}' + values.append('') + self.checkParams(widget, name, *values) + errmsg = 'bad relief "{}": must be %s, or %s' % ( + ', '.join(values[:-1]), + values[-1] or '""') if tk_version < (8, 6): errmsg = None self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) From 59e0b401a68ba9d26a4d41dab8156d95824dfcf1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 7 Jun 2024 17:05:02 +0300 Subject: [PATCH 25/30] Fix some typos. --- Lib/test/test_ttk/test_widgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index c33a29187c0935..31bf73dd30c9b3 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -289,8 +289,8 @@ def cb_test(): cbtn['command'] = '' res = cbtn.invoke() - if tk_version >= (8, 7): - self.assertFalse(res, ()) + if tk_version >= (8, 7) and self.wantobjects: + self.assertEqual(res, ()) else: self.assertEqual(str(res), '') self.assertLessEqual(len(success), 1) @@ -986,7 +986,7 @@ def test_configure_width(self): widget = self.create() if tk_version >= (8, 7): self.checkPixelsParam(widget, 'width', 402, -402, 0, '3c', conv=False) - self.checkPixelsParam(widget, 'height', 401.2, 402.6, conv=False) + self.checkPixelsParam(widget, 'width', 401.2, 402.6, conv=False) else: self.checkIntegerParam(widget, 'width', 402, -402, 0) From be01369d2e017e4c37550c1a0db5af9be823f632 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Jun 2024 10:33:33 +0300 Subject: [PATCH 26/30] Update Tcl/Tk. --- .../test_tkinter/test_geometry_managers.py | 4 +- Lib/test/test_tkinter/test_widgets.py | 45 +++++++++++++------ Lib/test/test_tkinter/widget_tests.py | 29 ++++++++---- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index e2a3301391cfe5..46cd278f510600 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -321,7 +321,7 @@ def test_place_configure_x(self): self.root.update() self.assertEqual(f2.winfo_x(), 190) with self.assertRaisesRegex(TclError, - EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('spam')): + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('spam')): f2.place_configure(in_=f, x='spam') def test_place_configure_y(self): @@ -339,7 +339,7 @@ def test_place_configure_y(self): self.root.update() self.assertEqual(f2.winfo_y(), 110) with self.assertRaisesRegex(TclError, - EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG.format('spam')): + EXPECTED_SCREEN_DISTANCE_ERRMSG.format('spam')): f2.place_configure(in_=f, y='spam') def test_place_configure_relx(self): diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 34faeb0302c062..2608d0d6e4ef86 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -144,7 +144,9 @@ def test_configure_labelwidget(self): class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests): _conv_pixels = False - clip_highlightthickness = False + _clip_highlightthickness = tk_version >= (8, 7) + _clip_pad = tk_version >= (8, 7) + _clip_borderwidth = tk_version >= (8, 7) @add_standard_options(StandardOptionsTests) @@ -276,7 +278,9 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase): 'underline', 'width', 'wraplength', ) _conv_pixels = round - clip_highlightthickness = True + _clip_highlightthickness = True + _clip_pad = True + _clip_borderwidth = False def create(self, **kwargs): return tkinter.Menubutton(self.root, **kwargs) @@ -310,16 +314,6 @@ def test_configure_menu(self): self.checkParam(widget, 'menu', menu, eq=widget_eq) menu.destroy() - def test_configure_padx(self): - widget = self.create() - self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m') - self.checkParam(widget, 'padx', -2, expected=0) - - def test_configure_pady(self): - widget = self.create() - self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m') - self.checkParam(widget, 'pady', -2, expected=0) - def test_configure_width(self): widget = self.create() self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str) @@ -1188,7 +1182,9 @@ def test_configure_activerelief(self): def test_configure_elementborderwidth(self): widget = self.create() - self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m') + self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, '1m') + expected = self._default_pixels if tk_version >= (8, 7) else -2 + self.checkParam(widget, 'elementborderwidth', -2, expected=expected) def test_configure_orient(self): widget = self.create() @@ -1476,7 +1472,8 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase): _conv_pad_pixels = False if tk_version >= (8, 7): _conv_pixels = False - clip_highlightthickness = False + _clip_pad = tk_version >= (8, 7) + _clip_borderwidth = tk_version >= (8, 7) def create(self, **kwargs): return tkinter.Message(self.root, **kwargs) @@ -1485,6 +1482,26 @@ def test_configure_aspect(self): widget = self.create() self.checkIntegerParam(widget, 'aspect', 250, 0, -300) + def test_configure_padx(self): + widget = self.create() + self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m', + conv=self._conv_pad_pixels) + expected = self._default_pixels if self._clip_pad else -2 + self.checkParam(widget, 'padx', -2, expected=expected) + + def test_configure_pady(self): + widget = self.create() + self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m', + conv=self._conv_pad_pixels) + expected = self._default_pixels if self._clip_pad else -2 + self.checkParam(widget, 'pady', -2, expected=expected) + + def test_configure_width(self): + widget = self.create() + self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, 0, '5i') + expected = 0 if tk_version >= (8, 7) else -402 + self.checkParam(widget, 'width', -402, expected=expected) + class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index 5f7fc3d5485d0a..c9d617d6731332 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -10,10 +10,13 @@ _sentinel = object() class AbstractWidgetTest(AbstractTkTest): + _default_pixels = '' if tk_version >= (9, 0) else -1 if tk_version >= (8, 7) else '' _conv_pixels = round _conv_pad_pixels = None _stringify = False - clip_highlightthickness = True + _clip_highlightthickness = True + _clip_pad = False + _clip_borderwidth = False @property def scaling(self): @@ -260,9 +263,14 @@ def test_configure_bitmap(self): def test_configure_borderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'borderwidth', - 0, 1.3, 2.6, 6, -2, '10p') + 0, 1.3, 2.6, 6, '10p') + expected = 0 if self._clip_borderwidth else -2 + self.checkParam(widget, 'borderwidth', -2, expected=expected, + conv=self._conv_pixels) if 'bd' in self.OPTIONS: - self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, -2, '10p') + self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, '10p') + self.checkParam(widget, 'bd', -2, expected=expected, + conv=self._conv_pixels) def test_configure_compound(self): widget = self.create() @@ -306,7 +314,7 @@ def test_configure_highlightthickness(self): widget = self.create() self.checkPixelsParam(widget, 'highlightthickness', 0, 1.3, 2.6, 6, '10p') - expected = 0 if self.clip_highlightthickness else -2 + expected = 0 if self._clip_highlightthickness else -2 self.checkParam(widget, 'highlightthickness', -2, expected=expected, conv=self._conv_pixels) @@ -351,13 +359,19 @@ def test_configure_orient(self): def test_configure_padx(self): widget = self.create() - self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m', + self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m', conv=self._conv_pad_pixels) + expected = 0 if self._clip_pad else -2 + self.checkParam(widget, 'padx', -2, expected=expected, + conv=self._conv_pad_pixels) def test_configure_pady(self): widget = self.create() - self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m', + self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m', conv=self._conv_pad_pixels) + expected = 0 if self._clip_pad else -2 + self.checkParam(widget, 'pady', -2, expected=expected, + conv=self._conv_pad_pixels) def test_configure_relief(self): widget = self.create() @@ -413,9 +427,8 @@ def test_configure_underline(self): self.checkParams(widget, 'underline', 0, 1, 10) if tk_version >= (8, 7): is_ttk = widget.__class__.__module__ == 'tkinter.ttk' - default = -1 if tk_version == (8, 7) else '' self.checkParam(widget, 'underline', '', - expected='' if is_ttk else default) + expected='' if is_ttk else self._default_pixels) self.checkParam(widget, 'underline', '5+2', expected='5+2' if is_ttk else 7) self.checkParam(widget, 'underline', '5-2', From 0c7d8519a38b8e12f7d3e6f0e947ffbf4a99bfe9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Jun 2024 15:05:38 +0300 Subject: [PATCH 27/30] Refactor. --- Lib/test/test_tkinter/test_widgets.py | 8 ++---- Lib/test/test_tkinter/widget_tests.py | 11 +++++-- Lib/test/test_ttk/test_widgets.py | 41 ++++++++------------------- 3 files changed, 23 insertions(+), 37 deletions(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 2608d0d6e4ef86..e6c4df27453d84 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1419,12 +1419,10 @@ def test_configure_title(self): def test_configure_type(self): widget = self.create() - if tk_version >= (8, 7): - values = ('menubar', 'normal', 'tearoff') - else: - values = ('normal', 'tearoff', 'menubar') + values = ('normal', 'tearoff', 'menubar') self.checkEnumParam(widget, 'type', *values, - allow_empty=tk_version < (8, 7)) + allow_empty=tk_version < (8, 7), + sort=tk_version >= (8, 7)) def test_entryconfigure(self): m1 = self.create() diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index c9d617d6731332..e65675c53a9627 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -119,9 +119,14 @@ def command(*args): def checkEnumParam(self, widget, name, *values, errmsg=None, allow_empty=False, fullname=None, - **kwargs): + sort=False, **kwargs): self.checkParams(widget, name, *values, **kwargs) if errmsg is None: + if sort: + if values[-1]: + values = tuple(sorted(values)) + else: + values = tuple(sorted(values[:-1])) + ('',) errmsg2 = ' %s "{}": must be %s%s or %s' % ( fullname or name, ', '.join(values[:-1]), @@ -151,9 +156,9 @@ def checkPixelsParam(self, widget, name, *values, self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) def checkReliefParam(self, widget, name, *, allow_empty=False): - values = ['flat', 'groove', 'raised', 'ridge', 'solid', 'sunken'] + values = ('flat', 'groove', 'raised', 'ridge', 'solid', 'sunken') if allow_empty: - values.append('') + values += ('',) self.checkParams(widget, name, *values) errmsg = 'bad relief "{}": must be %s, or %s' % ( ', '.join(values[:-1]), diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 31bf73dd30c9b3..2eb2c446366517 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -177,9 +177,9 @@ def checkImageParam(self, widget, name): errmsg='image "spam" doesn\'t exist') def test_configure_compound(self): - values = 'none text image center top bottom left right'.split() + values = ('none', 'text', 'image', 'center', 'top', 'bottom', 'left', 'right') if tk_version >= (8, 7): - values.append('') + values += ('',) widget = self.create() self.checkEnumParam(widget, 'compound', *values, allow_empty=True) @@ -233,11 +233,9 @@ def create(self, **kwargs): def test_configure_default(self): widget = self.create() - if tk_version >= (8, 7): - values = ('active', 'disabled', 'normal') - else: - values = ('normal', 'active', 'disabled') - self.checkEnumParam(widget, 'default', *values) + values = ('normal', 'active', 'disabled') + self.checkEnumParam(widget, 'default', *values, + sort=tk_version >= (8, 7)) def test_invoke(self): success = [] @@ -790,11 +788,9 @@ def create(self, **kwargs): def test_configure_direction(self): widget = self.create() - if tk_version >= (8, 7): - values = 'above', 'below', 'flush', 'left', 'right' - else: - values = 'above', 'below', 'left', 'right', 'flush' - self.checkEnumParam(widget, 'direction', *values) + values = ('above', 'below', 'left', 'right', 'flush') + self.checkEnumParam(widget, 'direction', *values, + sort=tk_version >= (8, 7)) def test_configure_menu(self): widget = self.create() @@ -957,11 +953,14 @@ def create(self, **kwargs): return ttk.Scrollbar(self.root, **kwargs) -@add_standard_options(IntegerSizeTests, StandardTtkOptionsTests) +@add_standard_options(PixelSizeTests if tk_version >= (8, 7) else IntegerSizeTests, + StandardTtkOptionsTests) class NotebookTest(AbstractWidgetTest, unittest.TestCase): OPTIONS = ( 'class', 'cursor', 'height', 'padding', 'style', 'takefocus', 'width', ) + if tk_version >= (8, 7): + _conv_pixels = False def setUp(self): super().setUp() @@ -974,22 +973,6 @@ def setUp(self): def create(self, **kwargs): return ttk.Notebook(self.root, **kwargs) - def test_configure_height(self): - widget = self.create() - if tk_version >= (8, 7): - self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False) - self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=False) - else: - self.checkIntegerParam(widget, 'height', 100, -100, 0) - - def test_configure_width(self): - widget = self.create() - if tk_version >= (8, 7): - self.checkPixelsParam(widget, 'width', 402, -402, 0, '3c', conv=False) - self.checkPixelsParam(widget, 'width', 401.2, 402.6, conv=False) - else: - self.checkIntegerParam(widget, 'width', 402, -402, 0) - def test_tab_identifiers(self): self.nb.forget(0) self.nb.hide(self.child2) From c9ab1a5a2145475c8c03d6b9e41524d8778608a5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Jun 2024 18:29:26 +0300 Subject: [PATCH 28/30] Polishing. --- Lib/test/test_tkinter/test_geometry_managers.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index 46cd278f510600..d71a634a767310 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -10,6 +10,8 @@ requires('gui') +EXPECTED_FLOAT_ERRMSG = 'expected floating-point number but got "{}"' +EXPECTED_FLOAT_OR_EMPTY_ERRMSG = 'expected floating-point number (or "" )?but got "{}"' EXPECTED_SCREEN_DISTANCE_ERRMSG = '(bad|expected) screen distance (but got )?"{}"' EXPECTED_SCREEN_DISTANCE_OR_EMPTY_ERRMSG = '(bad|expected) screen distance (or "" but got )?"{}"' @@ -356,8 +358,7 @@ def test_place_configure_relx(self): self.assertEqual(f2.place_info()['relx'], '1') self.root.update() self.assertEqual(f2.winfo_x(), 200) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "spam"'): + with self.assertRaisesRegex(TclError, EXPECTED_FLOAT_ERRMSG.format('spam')): f2.place_configure(in_=f, relx='spam') def test_place_configure_rely(self): @@ -374,8 +375,7 @@ def test_place_configure_rely(self): self.assertEqual(f2.place_info()['rely'], '1') self.root.update() self.assertEqual(f2.winfo_y(), 120) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - 'but got "spam"'): + with self.assertRaisesRegex(TclError, EXPECTED_FLOAT_ERRMSG.format('spam')): f2.place_configure(in_=f, rely='spam') def test_place_configure_anchor(self): @@ -420,8 +420,7 @@ def test_place_configure_relwidth(self): f2.place_configure(relwidth='') self.root.update() self.assertEqual(f2.winfo_width(), 30) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - '(or "" )?but got "abcd"'): + with self.assertRaisesRegex(TclError, EXPECTED_FLOAT_OR_EMPTY_ERRMSG.format('abcd')): f2.place_configure(relwidth='abcd') def test_place_configure_relheight(self): @@ -432,8 +431,7 @@ def test_place_configure_relheight(self): f2.place_configure(relheight='') self.root.update() self.assertEqual(f2.winfo_height(), 60) - with self.assertRaisesRegex(TclError, 'expected floating-point number ' - '(or "" )?but got "abcd"'): + with self.assertRaisesRegex(TclError, EXPECTED_FLOAT_OR_EMPTY_ERRMSG.format('abcd')): f2.place_configure(relheight='abcd') def test_place_configure_bordermode(self): From c25d025a4016d78fd704f3c5bbaa6ab86385eaf1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Jun 2024 19:54:28 +0300 Subject: [PATCH 29/30] Polishing. --- Lib/test/test_tkinter/test_widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index e6c4df27453d84..64ea87e647cf8b 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1189,7 +1189,7 @@ def test_configure_elementborderwidth(self): def test_configure_orient(self): widget = self.create() self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal', - errmsg='bad orientation "{}": must be vertical or horizontal') + fullname='orientation', allow_empty=True) def test_activate(self): sb = self.create() From 7dc7b5adc681c03859c34c7ef722603570d752e9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Jun 2024 20:32:12 +0300 Subject: [PATCH 30/30] Match full errmsg. --- Lib/test/test_tkinter/widget_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index e65675c53a9627..eef2efb3856b1f 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -62,6 +62,7 @@ def checkInvalidParam(self, widget, name, value, errmsg=None): orig = widget[name] if errmsg is not None: errmsg = errmsg.format(re.escape(str(value))) + errmsg = fr'\A{errmsg}\Z' with self.assertRaisesRegex(tkinter.TclError, errmsg or ''): widget[name] = value self.assertEqual(widget[name], orig)