]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-153741: Harden IDLE GUI tests for newer Tk and display scaling (#153742)
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 22 Jul 2026 01:16:50 +0000 (04:16 +0300)
committerGitHub <noreply@github.com>
Wed, 22 Jul 2026 01:16:50 +0000 (21:16 -0400)
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().

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)