From 6e00bb472d180c57c01844648ec73ebf234c6db0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 30 Jun 2026 08:41:40 +0300 Subject: [PATCH] Use tkinter wrapper methods instead of raw Tcl calls in turtle and IDLE (GH-152414) * turtle: wm_attributes(topmost=...); * idlelib.macosx: winfo_server(); * idlelib tests: after_info(). (cherry picked from commit fc866dc84ec430ab22d60609520f7ab27267baef) Co-authored-by: Serhiy Storchaka Co-authored-by: Claude Opus 4.8 --- Lib/idlelib/idle_test/template.py | 2 +- Lib/idlelib/idle_test/test_codecontext.py | 4 ++-- Lib/idlelib/idle_test/test_colorizer.py | 10 +++++----- Lib/idlelib/idle_test/test_editor.py | 6 +++--- Lib/idlelib/idle_test/test_filelist.py | 2 +- Lib/idlelib/idle_test/test_iomenu.py | 2 +- Lib/idlelib/idle_test/test_multicall.py | 2 +- Lib/idlelib/idle_test/test_pyshell.py | 2 +- Lib/idlelib/idle_test/test_runscript.py | 2 +- Lib/idlelib/idle_test/test_stackviewer.py | 2 +- Lib/idlelib/idle_test/test_window.py | 2 +- Lib/idlelib/idle_test/test_zoomheight.py | 2 +- Lib/idlelib/idle_test/test_zzdummy.py | 2 +- Lib/idlelib/idle_test/test_zzdummy_user.py | 2 +- Lib/idlelib/macosx.py | 2 +- Lib/turtle.py | 4 ++-- 16 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Lib/idlelib/idle_test/template.py b/Lib/idlelib/idle_test/template.py index 725a55b9c47230..69a2af22efa149 100644 --- a/Lib/idlelib/idle_test/template.py +++ b/Lib/idlelib/idle_test/template.py @@ -17,7 +17,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_codecontext.py b/Lib/idlelib/idle_test/test_codecontext.py index 6969ad73b01a81..3f070da022384e 100644 --- a/Lib/idlelib/idle_test/test_codecontext.py +++ b/Lib/idlelib/idle_test/test_codecontext.py @@ -127,7 +127,7 @@ def test_del_with_timer(self): timer = self.cc.t1 = self.text.after(10000, lambda: None) self.cc.__del__() with self.assertRaises(TclError) as cm: - self.root.tk.call('after', 'info', timer) + self.root.after_info(timer) self.assertIn("doesn't exist", str(cm.exception)) def test_reload(self): @@ -151,7 +151,7 @@ def test_toggle_code_context_event(self): eq(cc.context['bg'], self.highlight_cfg['background']) eq(cc.context.get('1.0', 'end-1c'), '') eq(cc.editwin.label, 'Hide Code Context') - eq(self.root.tk.call('after', 'info', self.cc.t1)[1], 'timer') + eq(self.root.after_info(self.cc.t1)[1], 'timer') # Toggle off. toggle() diff --git a/Lib/idlelib/idle_test/test_colorizer.py b/Lib/idlelib/idle_test/test_colorizer.py index fb6ee825086750..4d9e6bd887c5b8 100644 --- a/Lib/idlelib/idle_test/test_colorizer.py +++ b/Lib/idlelib/idle_test/test_colorizer.py @@ -260,7 +260,7 @@ def test_notify_range(self): # Colorizing already scheduled. save_id = color.after_id - eq(self.root.tk.call('after', 'info', save_id)[1], 'timer') + eq(self.root.after_info(save_id)[1], 'timer') self.assertFalse(color.colorizing) self.assertFalse(color.stop_colorizing) self.assertTrue(color.allow_colorizing) @@ -277,7 +277,7 @@ def test_notify_range(self): color.notify_range('1.0', '1.0+3c') self.assertTrue(color.stop_colorizing) self.assertIsNotNone(color.after_id) - eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer') + eq(self.root.after_info(color.after_id)[1], 'timer') # New event scheduled. self.assertNotEqual(color.after_id, save_id) @@ -297,7 +297,7 @@ def test_toggle_colorize_event(self): self.assertFalse(color.colorizing) self.assertFalse(color.stop_colorizing) self.assertTrue(color.allow_colorizing) - eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer') + eq(self.root.after_info(color.after_id)[1], 'timer') # Toggle colorizing off. color.toggle_colorize_event() @@ -324,7 +324,7 @@ def test_toggle_colorize_event(self): # Toggle on while colorizing not in progress. color.colorizing = False color.toggle_colorize_event() - eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer') + eq(self.root.after_info(color.after_id)[1], 'timer') self.assertFalse(color.colorizing) self.assertTrue(color.stop_colorizing) self.assertTrue(color.allow_colorizing) @@ -363,7 +363,7 @@ def test_recolorize(self, mock_recmain): mock_recmain.assert_called() eq(mock_recmain.call_count, 1) # Rescheduled when TODO tag still exists. - eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer') + eq(self.root.after_info(color.after_id)[1], 'timer') # No changes to text, so no scheduling added. text.tag_remove('TODO', '1.0', 'end') diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 0dfe2f3c58befa..e28ee549f180aa 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -20,7 +20,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) cls.root.destroy() del cls.root @@ -114,7 +114,7 @@ def tearDownClass(cls): cls.window._close() del cls.window cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) cls.root.destroy() del cls.root @@ -225,7 +225,7 @@ def tearDownClass(cls): cls.window._close() del cls.window cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_filelist.py b/Lib/idlelib/idle_test/test_filelist.py index 731f1975e50e23..e22cc3eced3082 100644 --- a/Lib/idlelib/idle_test/test_filelist.py +++ b/Lib/idlelib/idle_test/test_filelist.py @@ -16,7 +16,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_iomenu.py b/Lib/idlelib/idle_test/test_iomenu.py index 80f72bdfe5ff0e..90a23620354f31 100644 --- a/Lib/idlelib/idle_test/test_iomenu.py +++ b/Lib/idlelib/idle_test/test_iomenu.py @@ -30,7 +30,7 @@ def tearDownClass(cls): cls.editwin._close() del cls.editwin cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_multicall.py b/Lib/idlelib/idle_test/test_multicall.py index 67f28db6b0875c..7d73761cfdfee8 100644 --- a/Lib/idlelib/idle_test/test_multicall.py +++ b/Lib/idlelib/idle_test/test_multicall.py @@ -19,7 +19,7 @@ def setUpClass(cls): def tearDownClass(cls): del cls.mc cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_pyshell.py b/Lib/idlelib/idle_test/test_pyshell.py index 706703965bffd6..51f7691eefe9d5 100644 --- a/Lib/idlelib/idle_test/test_pyshell.py +++ b/Lib/idlelib/idle_test/test_pyshell.py @@ -40,7 +40,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): #cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_runscript.py b/Lib/idlelib/idle_test/test_runscript.py index 5fc60185a663e8..63086bfa4a404e 100644 --- a/Lib/idlelib/idle_test/test_runscript.py +++ b/Lib/idlelib/idle_test/test_runscript.py @@ -18,7 +18,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index 55f510382bf4c3..2434d38e4ffe83 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -21,7 +21,7 @@ def setUpClass(cls): def tearDownClass(cls): cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_window.py b/Lib/idlelib/idle_test/test_window.py index 5a2645b9cc27dc..9b56d321a407d6 100644 --- a/Lib/idlelib/idle_test/test_window.py +++ b/Lib/idlelib/idle_test/test_window.py @@ -29,7 +29,7 @@ def setUpClass(cls): def tearDownClass(cls): window.registry = window.WindowList() cls.root.update_idletasks() -## for id in cls.root.tk.call('after', 'info'): +## for id in cls.root.after_info(): ## cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_zoomheight.py b/Lib/idlelib/idle_test/test_zoomheight.py index aa5bdfb4fbd4c6..3b97c34d4ab29d 100644 --- a/Lib/idlelib/idle_test/test_zoomheight.py +++ b/Lib/idlelib/idle_test/test_zoomheight.py @@ -21,7 +21,7 @@ def setUpClass(cls): def tearDownClass(cls): cls.editwin._close() cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_zzdummy.py b/Lib/idlelib/idle_test/test_zzdummy.py index 14c343cf9b3087..c8e7dd6941b589 100644 --- a/Lib/idlelib/idle_test/test_zzdummy.py +++ b/Lib/idlelib/idle_test/test_zzdummy.py @@ -135,7 +135,7 @@ def tearDownClass(cls): zzdummy.idleConf.userCfg = usercfg del cls.editor, cls.text cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/idle_test/test_zzdummy_user.py b/Lib/idlelib/idle_test/test_zzdummy_user.py index 1d3f2ac3096fb0..a3476bf52bc588 100644 --- a/Lib/idlelib/idle_test/test_zzdummy_user.py +++ b/Lib/idlelib/idle_test/test_zzdummy_user.py @@ -68,7 +68,7 @@ def tearDownClass(cls): zzdummy.idleConf.userCfg = real_usercfg del cls.editor, cls.text cls.root.update_idletasks() - for id in cls.root.tk.call('after', 'info'): + for id in cls.root.after_info(): cls.root.after_cancel(id) # Need for EditorWindow. cls.root.destroy() del cls.root diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 332952f4572cbd..428e49f3eb7d8e 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -39,7 +39,7 @@ def _init_tk_type(): _tk_type = "xquartz" elif 'aqua' not in ws: _tk_type = "other" - elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + elif 'AppKit' in root.winfo_server(): _tk_type = "cocoa" else: _tk_type = "carbon" diff --git a/Lib/turtle.py b/Lib/turtle.py index b52d681b3af1c3..ae5be9fe7039d5 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -989,8 +989,8 @@ def __init__(self, cv, mode=_CFG["mode"], # the Turtle window will show behind the Terminal window when you # start the demo from the command line. rootwindow = cv.winfo_toplevel() - rootwindow.call('wm', 'attributes', '.', '-topmost', '1') - rootwindow.call('wm', 'attributes', '.', '-topmost', '0') + rootwindow.wm_attributes(topmost=True) + rootwindow.wm_attributes(topmost=False) def clear(self): """Delete all drawings and all turtles from the TurtleScreen.