]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-153741: Harden IDLE GUI tests for newer Tk and display scaling (GH-153742...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 22 Jul 2026 02:33:58 +0000 (04:33 +0200)
committerGitHub <noreply@github.com>
Wed, 22 Jul 2026 02:33:58 +0000 (02:33 +0000)
gh-153741: Harden IDLE GUI tests for newer Tk and display scaling (GH-153742)

In test_sidebar.test_mousewheel, only use the X11 <Button-4>/<Button-5> events when testing on
x11 Tk before 8.7.  Otherwise, use <Mousewheel> as on other systems.

In test_configdialog, assert the 'disabled' state flag alone instead of
the exact ttk state tuple (which transient pointer states break), and
restore the tests' method masks with addCleanup().
(cherry picked from commit a2581ebc7a93ec573f64d3a5e29cbd9053de7a1f)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lib/idlelib/idle_test/test_configdialog.py
Lib/idlelib/idle_test/test_sidebar.py

index c68fd304ea4235eba9ca70f0e81a40ab19e3aac9..696a3b2f8f1bc238fa820bc9c86713f8c8187179 100644 (file)
@@ -244,6 +244,7 @@ class FontPageTest(unittest.TestCase):
 
     def test_set_samples(self):
         d = self.page
+        self.addCleanup(setattr, d, 'set_samples', Func())  # Re-mask for other tests.
         del d.set_samples  # Unmask method for test
         orig_samples = d.font_sample, d.highlight_sample
         d.font_sample, d.highlight_sample = {}, {}
@@ -257,7 +258,6 @@ class FontPageTest(unittest.TestCase):
         self.assertTrue(d.font_sample == d.highlight_sample == expected)
 
         d.font_sample, d.highlight_sample = orig_samples
-        d.set_samples = Func()  # Re-mask for other tests.
 
 
 class HighPageTest(unittest.TestCase):
@@ -307,7 +307,7 @@ class HighPageTest(unittest.TestCase):
         # builtinlist sets variable builtin_name to the CurrentTheme default.
         eq(d.builtin_name.get(), 'IDLE Classic')
         eq(d.custom_name.get(), '- no custom themes -')
-        eq(d.custom_theme_on.state(), ('disabled',))
+        self.assertIn('disabled', d.custom_theme_on.state())
         eq(d.set_theme_type.called, 1)
         eq(d.paint_theme_sample.called, 1)
         eq(d.set_highlight_target.called, 1)
@@ -495,6 +495,7 @@ class HighPageTest(unittest.TestCase):
     def test_set_theme_type(self):
         eq = self.assertEqual
         d = self.page
+        self.addCleanup(setattr, d, 'set_theme_type', Func())  # Re-mask method.
         del d.set_theme_type
 
         # Builtin theme selected.
@@ -502,16 +503,15 @@ class HighPageTest(unittest.TestCase):
         d.set_theme_type()
         eq(d.builtinlist['state'], NORMAL)
         eq(d.customlist['state'], DISABLED)
-        eq(d.button_delete_custom.state(), ('disabled',))
+        self.assertIn('disabled', d.button_delete_custom.state())
 
         # Custom theme selected.
         d.theme_source.set(False)
         d.set_theme_type()
         eq(d.builtinlist['state'], DISABLED)
-        eq(d.custom_theme_on.state(), ('selected',))
+        self.assertNotIn('disabled', d.custom_theme_on.state())
         eq(d.customlist['state'], NORMAL)
-        eq(d.button_delete_custom.state(), ())
-        d.set_theme_type = Func()
+        self.assertNotIn('disabled', d.button_delete_custom.state())
 
     def test_get_color(self):
         eq = self.assertEqual
@@ -637,24 +637,23 @@ class HighPageTest(unittest.TestCase):
     def test_set_highlight_target(self):
         eq = self.assertEqual
         d = self.page
+        self.addCleanup(setattr, d, 'set_highlight_target', Func())  # Re-mask method.
         del d.set_highlight_target
 
         # Target is cursor.
         d.highlight_target.set('Cursor')
-        eq(d.fg_on.state(), ('disabled', 'selected'))
-        eq(d.bg_on.state(), ('disabled',))
+        self.assertIn('disabled', d.fg_on.state())
+        self.assertIn('disabled', d.bg_on.state())
         self.assertTrue(d.fg_bg_toggle)
         eq(d.set_color_sample.called, 1)
 
         # Target is not cursor.
         d.highlight_target.set('Comment')
-        eq(d.fg_on.state(), ('selected',))
-        eq(d.bg_on.state(), ())
+        self.assertNotIn('disabled', d.fg_on.state())
+        self.assertNotIn('disabled', d.bg_on.state())
         self.assertTrue(d.fg_bg_toggle)
         eq(d.set_color_sample.called, 2)
 
-        d.set_highlight_target = Func()
-
     def test_set_color_sample_binding(self):
         d = self.page
         scs = d.set_color_sample
@@ -667,6 +666,7 @@ class HighPageTest(unittest.TestCase):
 
     def test_set_color_sample(self):
         d = self.page
+        self.addCleanup(setattr, d, 'set_color_sample', Func())  # Re-mask method.
         del d.set_color_sample
         d.highlight_target.set('Selected Text')
         d.fg_bg_toggle.set(True)
@@ -674,7 +674,6 @@ class HighPageTest(unittest.TestCase):
         self.assertEqual(
                 d.style.lookup(d.frame_color_set['style'], 'background'),
                 d.highlight_sample.tag_cget('hilite', 'foreground'))
-        d.set_color_sample = Func()
 
     def test_paint_theme_sample(self):
         eq = self.assertEqual
@@ -745,7 +744,7 @@ class HighPageTest(unittest.TestCase):
         eq(yesno.called, 2)
         self.assertNotIn(theme_name, highpage)
         eq(idleConf.GetSectionList('user', 'highlight'), [theme_name2])
-        eq(d.custom_theme_on.state(), ())
+        self.assertNotIn('disabled', d.custom_theme_on.state())
         eq(d.custom_name.get(), theme_name2)
         eq(dialog.deactivate_current_config.called, 1)
         eq(dialog.activate_config_changes.called, 1)
@@ -758,7 +757,7 @@ class HighPageTest(unittest.TestCase):
         eq(yesno.called, 3)
         self.assertNotIn(theme_name, highpage)
         eq(idleConf.GetSectionList('user', 'highlight'), [])
-        eq(d.custom_theme_on.state(), ('disabled',))
+        self.assertIn('disabled', d.custom_theme_on.state())
         eq(d.custom_name.get(), '- no custom themes -')
         eq(dialog.deactivate_current_config.called, 2)
         eq(dialog.activate_config_changes.called, 2)
@@ -809,7 +808,7 @@ class KeysPageTest(unittest.TestCase):
         # builtinlist sets variable builtin_name to the CurrentKeys default.
         eq(d.builtin_name.get(), 'IDLE Classic OSX')
         eq(d.custom_name.get(), '- no custom keys -')
-        eq(d.custom_keyset_on.state(), ('disabled',))
+        self.assertIn('disabled', d.custom_keyset_on.state())
         eq(d.set_keys_type.called, 1)
         eq(d.load_keys_list.called, 1)
         eq(d.load_keys_list.args, ('IDLE Classic OSX', ))
@@ -930,6 +929,7 @@ class KeysPageTest(unittest.TestCase):
     def test_set_keys_type(self):
         eq = self.assertEqual
         d = self.page
+        self.addCleanup(setattr, d, 'set_keys_type', Func())  # Re-mask method.
         del d.set_keys_type
 
         # Builtin keyset selected.
@@ -937,16 +937,15 @@ class KeysPageTest(unittest.TestCase):
         d.set_keys_type()
         eq(d.builtinlist['state'], NORMAL)
         eq(d.customlist['state'], DISABLED)
-        eq(d.button_delete_custom_keys.state(), ('disabled',))
+        self.assertIn('disabled', d.button_delete_custom_keys.state())
 
         # Custom keyset selected.
         d.keyset_source.set(False)
         d.set_keys_type()
         eq(d.builtinlist['state'], DISABLED)
-        eq(d.custom_keyset_on.state(), ('selected',))
+        self.assertNotIn('disabled', d.custom_keyset_on.state())
         eq(d.customlist['state'], NORMAL)
-        eq(d.button_delete_custom_keys.state(), ())
-        d.set_keys_type = Func()
+        self.assertNotIn('disabled', d.button_delete_custom_keys.state())
 
     def test_get_new_keys(self):
         eq = self.assertEqual
@@ -1043,7 +1042,7 @@ class KeysPageTest(unittest.TestCase):
         b.event_generate('<Button-1>', x=x, y=y)
         b.event_generate('<ButtonRelease-1>', x=x, y=y)
         self.assertEqual(b.get('anchor'), 'find')
-        self.assertEqual(d.button_new_keys.state(), ())
+        self.assertNotIn('disabled', d.button_new_keys.state())
 
     def test_create_new_key_set_and_save_new_key_set(self):
         eq = self.assertEqual
@@ -1080,6 +1079,7 @@ class KeysPageTest(unittest.TestCase):
         eq = self.assertEqual
         d = self.page
         gks = idleConf.GetKeySet = Func()
+        self.addCleanup(setattr, d, 'load_keys_list', Func())  # Re-mask method.
         del d.load_keys_list
         b = d.bindingslist
 
@@ -1115,7 +1115,6 @@ class KeysPageTest(unittest.TestCase):
         eq(b.get(0, 'end'), expected)
         eq(b.get('anchor'), 'spam - <Shift-Key-a>')
         eq(b.curselection(), (2, ))
-        d.load_keys_list = Func()
 
         del idleConf.GetKeySet
 
@@ -1156,7 +1155,7 @@ class KeysPageTest(unittest.TestCase):
         eq(yesno.called, 2)
         self.assertNotIn(keyset_name, keyspage)
         eq(idleConf.GetSectionList('user', 'keys'), [keyset_name2])
-        eq(d.custom_keyset_on.state(), ())
+        self.assertNotIn('disabled', d.custom_keyset_on.state())
         eq(d.custom_name.get(), keyset_name2)
         eq(dialog.deactivate_current_config.called, 1)
         eq(dialog.activate_config_changes.called, 1)
@@ -1169,7 +1168,7 @@ class KeysPageTest(unittest.TestCase):
         eq(yesno.called, 3)
         self.assertNotIn(keyset_name, keyspage)
         eq(idleConf.GetSectionList('user', 'keys'), [])
-        eq(d.custom_keyset_on.state(), ('disabled',))
+        self.assertIn('disabled', d.custom_keyset_on.state())
         eq(d.custom_name.get(), '- no custom keys -')
         eq(dialog.deactivate_current_config.called, 2)
         eq(dialog.activate_config_changes.called, 2)
@@ -1365,25 +1364,25 @@ class HelpSourceTest(unittest.TestCase):
         # Call with 0 items, 1 unselected item, 1 selected item.
         eq = self.assertEqual
         fr = self.frame
+        self.addCleanup(setattr, fr, 'set_add_delete_state', Func())  # Re-mask method.
         del fr.set_add_delete_state  # Unmask method.
         sad = fr.set_add_delete_state
         h = fr.helplist
 
         h.delete(0, 'end')
         sad()
-        eq(fr.button_helplist_edit.state(), ('disabled',))
-        eq(fr.button_helplist_remove.state(), ('disabled',))
+        self.assertIn('disabled', fr.button_helplist_edit.state())
+        self.assertIn('disabled', fr.button_helplist_remove.state())
 
         h.insert(0, 'source')
         sad()
-        eq(fr.button_helplist_edit.state(), ('disabled',))
-        eq(fr.button_helplist_remove.state(), ('disabled',))
+        self.assertIn('disabled', fr.button_helplist_edit.state())
+        self.assertIn('disabled', fr.button_helplist_remove.state())
 
         h.selection_set(0)
         sad()
-        eq(fr.button_helplist_edit.state(), ())
-        eq(fr.button_helplist_remove.state(), ())
-        fr.set_add_delete_state = Func()  # Mask method.
+        self.assertNotIn('disabled', fr.button_helplist_edit.state())
+        self.assertNotIn('disabled', fr.button_helplist_remove.state())
 
     def test_helplist_item_add(self):
         # Call without and twice with HelpSource result.
@@ -1461,6 +1460,7 @@ class HelpSourceTest(unittest.TestCase):
 
     def test_update_help_changes(self):
         fr = self.frame
+        self.addCleanup(setattr, fr, 'update_help_changes', Func())  # Re-mask method.
         del fr.update_help_changes
         fr.user_helplist.clear()
         fr.user_helplist.append(('name1', 'file1'))
@@ -1469,7 +1469,6 @@ class HelpSourceTest(unittest.TestCase):
         fr.update_help_changes()
         self.assertEqual(mainpage['HelpFiles'],
                          {'1': 'name1;file1', '2': 'name2;file2'})
-        fr.update_help_changes = Func()
 
 
 class VarTraceTest(unittest.TestCase):
index dc3431d8d8ef8870ce3647dfd32fe1ca49875767..df84554c4f1a5156fa07d1623449ff1a9c133a55 100644 (file)
@@ -689,11 +689,15 @@ class ShellSidebarTest(unittest.TestCase):
         last_lineno = get_end_linenumber(text)
         self.assertIsNotNone(text.dlineinfo(text.index(f'{last_lineno}.0')))
 
-        # Delta for <MouseWheel>, whose meaning is platform-dependent.
+        # Simulate a mouse wheel notch.  Tk 8.7 replaced the X11
+        # <Button-4>/<Button-5> wheel events with <MouseWheel> (whose delta is
+        # platform-dependent); older Tk on X11 still uses the button events.
+        x11_buttons = (sidebar.canvas._windowingsystem == 'x11'
+                       and tk.TkVersion < 8.7)
         delta = 1 if sidebar.canvas._windowingsystem == 'aqua' else 120
 
         # Scroll up.
-        if sidebar.canvas._windowingsystem == 'x11':
+        if x11_buttons:
             sidebar.canvas.event_generate('<Button-4>', x=0, y=0)
         else:
             sidebar.canvas.event_generate('<MouseWheel>', x=0, y=0, delta=delta)
@@ -701,7 +705,7 @@ class ShellSidebarTest(unittest.TestCase):
         self.assertIsNone(text.dlineinfo(text.index(f'{last_lineno}.0')))
 
         # Scroll back down.
-        if sidebar.canvas._windowingsystem == 'x11':
+        if x11_buttons:
             sidebar.canvas.event_generate('<Button-5>', x=0, y=0)
         else:
             sidebar.canvas.event_generate('<MouseWheel>', x=0, y=0, delta=-delta)