From a0bb7abe46aedbe480f4e8378f9a27111e0b39f5 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 14:39:24 +0100 Subject: [PATCH 01/15] gh-112898: Fix double close dialog with warning about unsafed files Without this changeset I get two consecutive dialogs asking if I want to save an unsafed file, when choosing "Cancel" in the first one. --- Lib/idlelib/macosx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 332952f4572cbd..683817d1ae38a2 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -221,7 +221,7 @@ def help_dialog(event=None): # The binding above doesn't reliably work on all versions of Tk # on macOS. Adding command definition below does seem to do the # right thing for now. - root.createcommand('::tk::mac::Quit', flist.close_all_callback) + root.createcommand('::tk::mac::Quit', lambda: "break") if isCarbonTk(): # for Carbon AquaTk, replace the default Tk apple menu From eda57502a75dd763413226a7bcaaa6a8d495313f Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 18:36:41 +0100 Subject: [PATCH 02/15] Actually work with various quit events (menu, shortcut, osascript) --- Lib/idlelib/config.py | 7 +++++++ Lib/idlelib/macosx.py | 4 +--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 92992fd9cce9cd..bcf429862f35a7 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -31,6 +31,7 @@ from tkinter.font import Font import idlelib +from idlelib import macosx class InvalidConfigType(Exception): pass class InvalidConfigSet(Exception): pass @@ -660,6 +661,12 @@ def GetCoreKeys(self, keySetName=None): '<>': [''], } + if sys.platform == "darwin": + # XXX: ^^^ This test should be macosx.isAquaTk(), + # but that has some side effect that results in not + # calling the quit event handler. + del keyBindings['<>'] + if keySetName: if not (self.userCfg['keys'].has_section(keySetName) or self.defaultCfg['keys'].has_section(keySetName)): diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 683817d1ae38a2..aca5c5f31cf0d7 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -216,12 +216,10 @@ def help_dialog(event=None): root.bind('<>', config_dialog) root.createcommand('::tk::mac::ShowPreferences', config_dialog) if flist: - root.bind('<>', flist.close_all_callback) - # The binding above doesn't reliably work on all versions of Tk # on macOS. Adding command definition below does seem to do the # right thing for now. - root.createcommand('::tk::mac::Quit', lambda: "break") + root.createcommand('::tk::mac::Quit', flist.close_all_callback) if isCarbonTk(): # for Carbon AquaTk, replace the default Tk apple menu From 3686a65339d191c10864bf1d72681aca12baa597 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 21:38:27 +0100 Subject: [PATCH 03/15] Remove comment that is no longer needed --- Lib/idlelib/macosx.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index aca5c5f31cf0d7..4ad09b3f854440 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -216,9 +216,6 @@ def help_dialog(event=None): root.bind('<>', config_dialog) root.createcommand('::tk::mac::ShowPreferences', config_dialog) if flist: - # The binding above doesn't reliably work on all versions of Tk - # on macOS. Adding command definition below does seem to do the - # right thing for now. root.createcommand('::tk::mac::Quit', flist.close_all_callback) if isCarbonTk(): From b305b36d0def3770bc7e4fa98c77e0fdedf2eb83 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 21:43:03 +0100 Subject: [PATCH 04/15] Restore working code path --- Lib/idlelib/config-keys.def | 4 ++-- Lib/idlelib/config.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/config-keys.def b/Lib/idlelib/config-keys.def index f71269b5b49f46..f6c8a75f2fcafd 100644 --- a/Lib/idlelib/config-keys.def +++ b/Lib/idlelib/config-keys.def @@ -193,7 +193,7 @@ cut= paste= beginning-of-line= center-insert= -close-all-windows= +close-all-windows= close-window= do-nothing= end-of-file= @@ -264,7 +264,7 @@ redo = close-window = restart-shell = save-window-as-file = -close-all-windows = +close-all-windows = view-restart = tabify-region = find-again = diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index bcf429862f35a7..7e524753f6b4c1 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -662,6 +662,7 @@ def GetCoreKeys(self, keySetName=None): } if sys.platform == "darwin": + #if macosx.isAquaTk(): # XXX: ^^^ This test should be macosx.isAquaTk(), # but that has some side effect that results in not # calling the quit event handler. From a84a2d7d6f1530647744f6e4fa519e704431bb8b Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 22:04:27 +0100 Subject: [PATCH 05/15] Crude hack to make sure the quit command is called --- Lib/idlelib/config-keys.def | 4 ++-- Lib/idlelib/macosx.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/config-keys.def b/Lib/idlelib/config-keys.def index f6c8a75f2fcafd..f71269b5b49f46 100644 --- a/Lib/idlelib/config-keys.def +++ b/Lib/idlelib/config-keys.def @@ -193,7 +193,7 @@ cut= paste= beginning-of-line= center-insert= -close-all-windows= +close-all-windows= close-window= do-nothing= end-of-file= @@ -264,7 +264,7 @@ redo = close-window = restart-shell = save-window-as-file = -close-all-windows = +close-all-windows = view-restart = tabify-region = find-again = diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 4ad09b3f854440..66298f27af9c69 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -13,6 +13,10 @@ _tk_type = None +def _on_quit(): + # on quit callback, overridden in setupApp + pass + def _init_tk_type(): """ Initialize _tk_type for isXyzTk functions. @@ -34,6 +38,12 @@ def _init_tk_type(): return root = tkinter.Tk() + + # Add an ::tk::mac::Quit command to the root because Tk + # seem to only call the quit command created in the + # first `tkinter.Tk` instance. + root.createcommand('::tk::mac::Quit', lambda: _on_quit()) + ws = root.tk.call('tk', 'windowingsystem') if 'x11' in ws: _tk_type = "xquartz" @@ -158,6 +168,7 @@ def overrideRootMenu(root, flist): from idlelib import mainmenu from idlelib import window + closeItem = mainmenu.menudefs[0][1][-2] # Remove the last 3 items of the file menu: a separator, close window and @@ -218,6 +229,11 @@ def help_dialog(event=None): if flist: root.createcommand('::tk::mac::Quit', flist.close_all_callback) + # Override the _on_quit helder, see comment in + # _init_tk_type for the background on this + global _on_quit + _on_quit = flist.close_all_callback + if isCarbonTk(): # for Carbon AquaTk, replace the default Tk apple menu menu = Menu(menubar, name='apple', tearoff=0) From 0ce7d86c31c4529d3c67af43aa86d1a9c1f10fd5 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 22:19:10 +0100 Subject: [PATCH 06/15] Remove unnecesary key setup --- Lib/idlelib/config.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 7e524753f6b4c1..65658161dce757 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -661,13 +661,6 @@ def GetCoreKeys(self, keySetName=None): '<>': [''], } - if sys.platform == "darwin": - #if macosx.isAquaTk(): - # XXX: ^^^ This test should be macosx.isAquaTk(), - # but that has some side effect that results in not - # calling the quit event handler. - del keyBindings['<>'] - if keySetName: if not (self.userCfg['keys'].has_section(keySetName) or self.defaultCfg['keys'].has_section(keySetName)): From ce08ba0f3283e1dd074e469cdaad34267c29d3b6 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 22:19:57 +0100 Subject: [PATCH 07/15] Remove unnecessary import --- Lib/idlelib/config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 65658161dce757..92992fd9cce9cd 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -31,7 +31,6 @@ from tkinter.font import Font import idlelib -from idlelib import macosx class InvalidConfigType(Exception): pass class InvalidConfigSet(Exception): pass From 92c1206c7ce3e92c0dc5dfefe97ed22c226768cb Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 22:20:49 +0100 Subject: [PATCH 08/15] typo --- Lib/idlelib/macosx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 66298f27af9c69..c0e85689908b01 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -229,7 +229,7 @@ def help_dialog(event=None): if flist: root.createcommand('::tk::mac::Quit', flist.close_all_callback) - # Override the _on_quit helder, see comment in + # Override the _on_quit helper, see comment in # _init_tk_type for the background on this global _on_quit _on_quit = flist.close_all_callback From 4cefbea797d7d6e415fc768e95df568d7b4403e6 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 27 Dec 2023 22:23:27 +0100 Subject: [PATCH 09/15] Getting lost ... Removing the <> bindings is still necessary to avoid double close pop-ups --- Lib/idlelib/config.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 92992fd9cce9cd..81cf51863c2ff6 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -31,6 +31,7 @@ from tkinter.font import Font import idlelib +from idlelib import macosx class InvalidConfigType(Exception): pass class InvalidConfigSet(Exception): pass @@ -660,6 +661,9 @@ def GetCoreKeys(self, keySetName=None): '<>': [''], } + if macosx.isAquaTk(): + del keyBindings['<>'] + if keySetName: if not (self.userCfg['keys'].has_section(keySetName) or self.defaultCfg['keys'].has_section(keySetName)): From bbdee67a1b80d1264e2162a145a23103a9235591 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 28 Dec 2023 11:18:46 +0100 Subject: [PATCH 10/15] Restructure code to avoid creating a temporary ``tkinter.Tk`` ``macosx.isAquaTk()`` needs access to Tk to query it. Before this changeset it created a temporary Tk instance. It turns out that the *first* instance of Tk created on macOS is special and must to be used to set up the commands to handle mac specific system events (file open, quit, ...). By restructuring the code a little we can avoid creating a temporary Tk object. --- Lib/idlelib/editor.py | 12 +++++++----- Lib/idlelib/idle_test/test_mainmenu.py | 2 +- Lib/idlelib/macosx.py | 25 +++++-------------------- Lib/idlelib/mainmenu.py | 13 ++++++++++++- Lib/idlelib/pyshell.py | 11 ++++++----- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 6ad383f460c7ee..8bf517d41fb6dd 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -452,7 +452,7 @@ def set_line_and_column(self, event=None): * mainmenu.menudefs - a list of tuples, one for each menubar item. Each tuple pairs a lower-case name and list of dropdown items. Each item is a name, virtual event pair or None for separator. - * mainmenu.default_keydefs - maps events to keys. + * mainmenu.get_default_keydefs() - maps events to keys. * text.keydefs - same. * cls.menu_specs - menubar name, titlecase display form pairs with Alt-hotkey indicator. A subset of menudefs items. @@ -901,7 +901,8 @@ def RemoveKeybindings(self): Leaves the default Tk Text keybindings. """ # Called from configdialog.deactivate_current_config. - self.mainmenu.default_keydefs = keydefs = idleConf.GetCurrentKeySet() + keydefs = idleConf.GetCurrentKeySet() + self.mainmenu.set_default_keydefs(keydefs) for event, keylist in keydefs.items(): self.text.event_delete(event, *keylist) for extensionName in self.get_standard_extension_names(): @@ -916,7 +917,8 @@ def ApplyKeybindings(self): Alse update hotkeys to current keyset. """ # Called from configdialog.activate_config_changes. - self.mainmenu.default_keydefs = keydefs = idleConf.GetCurrentKeySet() + keydefs = idleConf.GetCurrentKeySet() + self.mainmenu.set_default_keydefs(keydefs) self.apply_bindings() for extensionName in self.get_standard_extension_names(): xkeydefs = idleConf.GetExtensionBindings(extensionName) @@ -1204,7 +1206,7 @@ def load_extension(self, name): def apply_bindings(self, keydefs=None): """Add events with keys to self.text.""" if keydefs is None: - keydefs = self.mainmenu.default_keydefs + keydefs = self.mainmenu.get_default_keydefs() text = self.text text.keydefs = keydefs for event, keylist in keydefs.items(): @@ -1220,7 +1222,7 @@ def fill_menus(self, menudefs=None, keydefs=None): if menudefs is None: menudefs = self.mainmenu.menudefs if keydefs is None: - keydefs = self.mainmenu.default_keydefs + keydefs = self.mainmenu.get_default_keydefs() menudict = self.menudict text = self.text for mname, entrylist in menudefs: diff --git a/Lib/idlelib/idle_test/test_mainmenu.py b/Lib/idlelib/idle_test/test_mainmenu.py index 51d2accfe48a1c..cd64ee2fac10f8 100644 --- a/Lib/idlelib/idle_test/test_mainmenu.py +++ b/Lib/idlelib/idle_test/test_mainmenu.py @@ -15,7 +15,7 @@ def test_menudefs(self): self.assertEqual(actual, expect) def test_default_keydefs(self): - self.assertGreaterEqual(len(mainmenu.default_keydefs), 50) + self.assertGreaterEqual(len(mainmenu.get_default_keydefs()), 50) def test_tcl_indexes(self): # Test tcl patterns used to find menuitem to alter. diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index c0e85689908b01..8637e8ebf2c695 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -12,10 +12,7 @@ ## _tk_type and its initializer are private to this section. _tk_type = None - -def _on_quit(): - # on quit callback, overridden in setupApp - pass +_idle_root = None def _init_tk_type(): """ Initialize _tk_type for isXyzTk functions. @@ -37,23 +34,15 @@ def _init_tk_type(): _tk_type = "cocoa" return - root = tkinter.Tk() - - # Add an ::tk::mac::Quit command to the root because Tk - # seem to only call the quit command created in the - # first `tkinter.Tk` instance. - root.createcommand('::tk::mac::Quit', lambda: _on_quit()) - - ws = root.tk.call('tk', 'windowingsystem') + ws = _idle_root.tk.call('tk', 'windowingsystem') if 'x11' in ws: _tk_type = "xquartz" elif 'aqua' not in ws: _tk_type = "other" - elif 'AppKit' in root.tk.call('winfo', 'server', '.'): + elif 'AppKit' in _idle_root.tk.call('winfo', 'server', '.'): _tk_type = "cocoa" else: _tk_type = "carbon" - root.destroy() else: _tk_type = "other" return @@ -168,7 +157,6 @@ def overrideRootMenu(root, flist): from idlelib import mainmenu from idlelib import window - closeItem = mainmenu.menudefs[0][1][-2] # Remove the last 3 items of the file menu: a separator, close window and @@ -229,11 +217,6 @@ def help_dialog(event=None): if flist: root.createcommand('::tk::mac::Quit', flist.close_all_callback) - # Override the _on_quit helper, see comment in - # _init_tk_type for the background on this - global _on_quit - _on_quit = flist.close_all_callback - if isCarbonTk(): # for Carbon AquaTk, replace the default Tk apple menu menu = Menu(menubar, name='apple', tearoff=0) @@ -277,6 +260,8 @@ def setupApp(root, flist): isAquaTk(), isCarbonTk(), isCocoaTk(), isXQuartz() functions which are initialized here as well. """ + global _idle_root + _idle_root = root if isAquaTk(): hideTkConsole(root) overrideRootMenu(root, flist) diff --git a/Lib/idlelib/mainmenu.py b/Lib/idlelib/mainmenu.py index 91a32cebb513f9..1957cafdccc759 100644 --- a/Lib/idlelib/mainmenu.py +++ b/Lib/idlelib/mainmenu.py @@ -119,7 +119,18 @@ if find_spec('turtledemo'): menudefs[-1][1].append(('Turtle Demo', '<>')) -default_keydefs = idleConf.GetCurrentKeySet() +_default_keydefs = None + +def get_default_keydefs(): + global _default_keydefs + if _default_keydefs is None: + _default_keydefs = idleConf.GetCurrentKeySet() + return _default_keydefs + +def set_default_keydefs(keydefs): + global _default_keydefs + _default_keydefs = keydefs + if __name__ == '__main__': from unittest import main diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 1524fccd5d20f8..43977bf81d6058 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1611,6 +1611,12 @@ def main(): from idlelib.run import fix_scaling fix_scaling(root) + # start editor and/or shell windows: + fixwordbreaks(root) + fix_x11_paste(root) + flist = PyShellFileList(root) + macosx.setupApp(root, flist) + # set application icon icondir = os.path.join(os.path.dirname(__file__), 'Icons') if system() == 'Windows': @@ -1629,11 +1635,6 @@ def main(): for iconfile in iconfiles] root.wm_iconphoto(True, *icons) - # start editor and/or shell windows: - fixwordbreaks(root) - fix_x11_paste(root) - flist = PyShellFileList(root) - macosx.setupApp(root, flist) if enable_edit: if not (cmd or script): From ab7800a71cb04d99d6381609c018796c5fee532b Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 28 Dec 2023 11:31:37 +0100 Subject: [PATCH 11/15] Document why the close-all-windows keybinding is removed on macOS --- Lib/idlelib/config.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 81cf51863c2ff6..1acb1d69164a82 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -662,6 +662,14 @@ def GetCoreKeys(self, keySetName=None): } if macosx.isAquaTk(): + # There appears to be a system default binding for `Command-Q` + # on macOS that interferes with IDLE's setup. Don't add it + # to the key bindings an rely the default binding. + # + # Without this IDLE will prompt twice about closing a file with + # unsaved # changes when the user quits IDLE using the keyboard + # shortcutand then chooses "Cancel" the first time the dialog + # appears. del keyBindings['<>'] if keySetName: From 63087e30b7eb94853070dddd3abbc297b30d1092 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 28 Dec 2023 12:11:15 +0100 Subject: [PATCH 12/15] Fix test failure and lint warning --- Lib/idlelib/idle_test/test_macosx.py | 3 +++ Lib/idlelib/mainmenu.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/idlelib/idle_test/test_macosx.py b/Lib/idlelib/idle_test/test_macosx.py index 86da8849e5ca00..c80613dbd47300 100644 --- a/Lib/idlelib/idle_test/test_macosx.py +++ b/Lib/idlelib/idle_test/test_macosx.py @@ -41,6 +41,9 @@ def tearDownClass(cls): def test_init_sets_tktype(self): "Test that _init_tk_type sets _tk_type according to platform." for platform, types in ('darwin', alltypes), ('other', nontypes): + orig_root = None + macosx._idle_root = self.root + self.addCleanup(lambda: setattr(macosx, "_idle_root", orig_root)) with self.subTest(platform=platform): macosx.platform = platform macosx._tk_type = None diff --git a/Lib/idlelib/mainmenu.py b/Lib/idlelib/mainmenu.py index 1957cafdccc759..f81f996a4c3d25 100644 --- a/Lib/idlelib/mainmenu.py +++ b/Lib/idlelib/mainmenu.py @@ -130,7 +130,7 @@ def get_default_keydefs(): def set_default_keydefs(keydefs): global _default_keydefs _default_keydefs = keydefs - + if __name__ == '__main__': from unittest import main From 4794ee7ba640c05d93b455c97c7517e31766f71c Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Tue, 9 Jan 2024 11:41:03 +0100 Subject: [PATCH 13/15] The changes to macosx.py broke some of the tests Change the tests to ensure that the new invariants for macosx are met. This does assume that we're only interested in testing CocoaTk on macOS (which is IMHO a reasonable assumption) --- Lib/idlelib/idle_test/test_config.py | 5 +++ Lib/idlelib/idle_test/test_mainmenu.py | 8 +++++ Lib/idlelib/idle_test/test_squeezer.py | 45 ++++++++++++++------------ Lib/idlelib/macosx.py | 5 +++ 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Lib/idlelib/idle_test/test_config.py b/Lib/idlelib/idle_test/test_config.py index 6d75cf7aa67dcc..a859d759799d40 100644 --- a/Lib/idlelib/idle_test/test_config.py +++ b/Lib/idlelib/idle_test/test_config.py @@ -197,9 +197,14 @@ def setUpClass(cls): cls.orig_warn = config._warn config._warn = Func() + cls._patcher = mock.patch("idlelib.macosx._tk_type", new="cocoa" if sys.platform == "darwin" else "other") + cls._patcher.start() + + @classmethod def tearDownClass(cls): config._warn = cls.orig_warn + cls._patcher.stop() def new_config(self, _utest=False): return config.IdleConf(_utest=_utest) diff --git a/Lib/idlelib/idle_test/test_mainmenu.py b/Lib/idlelib/idle_test/test_mainmenu.py index cd64ee2fac10f8..bdc64d5ce43eaf 100644 --- a/Lib/idlelib/idle_test/test_mainmenu.py +++ b/Lib/idlelib/idle_test/test_mainmenu.py @@ -3,10 +3,18 @@ from idlelib import mainmenu import re +import sys import unittest +from unittest import mock class MainMenuTest(unittest.TestCase): + def setUp(self): + self._patcher = mock.patch("idlelib.macosx._tk_type", new="cocoa" if sys.platform == "darwin" else "other") + self._patcher.start() + + def tearDown(self): + self._patcher.stop() def test_menudefs(self): actual = [item[0] for item in mainmenu.menudefs] diff --git a/Lib/idlelib/idle_test/test_squeezer.py b/Lib/idlelib/idle_test/test_squeezer.py index 86c5d41b629719..29d2ba5820fc4d 100644 --- a/Lib/idlelib/idle_test/test_squeezer.py +++ b/Lib/idlelib/idle_test/test_squeezer.py @@ -1,5 +1,6 @@ "Test squeezer, coverage 95%" +import sys from textwrap import dedent from tkinter import Text, Tk import unittest @@ -22,8 +23,11 @@ def get_test_tk_root(test_instance): requires('gui') root = Tk() root.withdraw() + patcher = mock.patch("idlelib.macosx._idle_root", new=root) + patcher.start() def cleanup_root(): + patcher.stop() root.update_idletasks() root.destroy() test_instance.addCleanup(cleanup_root) @@ -170,27 +174,28 @@ def test_write_not_stdout(self): def test_write_stdout(self): """Test Squeezer's overriding of the EditorWindow's write() method.""" - editwin = self.make_mock_editor_window() - - for text in ['', 'TEXT']: - editwin.write = orig_write = Mock(return_value=SENTINEL_VALUE) - squeezer = self.make_squeezer_instance(editwin) - squeezer.auto_squeeze_min_lines = 50 - - self.assertEqual(squeezer.editwin.write(text, "stdout"), - SENTINEL_VALUE) - self.assertEqual(orig_write.call_count, 1) - orig_write.assert_called_with(text, "stdout") - self.assertEqual(len(squeezer.expandingbuttons), 0) - - for text in ['LONG TEXT' * 1000, 'MANY_LINES\n' * 100]: - editwin.write = orig_write = Mock(return_value=SENTINEL_VALUE) - squeezer = self.make_squeezer_instance(editwin) - squeezer.auto_squeeze_min_lines = 50 + with patch("idlelib.macosx._tk_type", new="cocoa" if sys.platform == "darwin" else "other"): + editwin = self.make_mock_editor_window() - self.assertEqual(squeezer.editwin.write(text, "stdout"), None) - self.assertEqual(orig_write.call_count, 0) - self.assertEqual(len(squeezer.expandingbuttons), 1) + for text in ['', 'TEXT']: + editwin.write = orig_write = Mock(return_value=SENTINEL_VALUE) + squeezer = self.make_squeezer_instance(editwin) + squeezer.auto_squeeze_min_lines = 50 + + self.assertEqual(squeezer.editwin.write(text, "stdout"), + SENTINEL_VALUE) + self.assertEqual(orig_write.call_count, 1) + orig_write.assert_called_with(text, "stdout") + self.assertEqual(len(squeezer.expandingbuttons), 0) + + for text in ['LONG TEXT' * 1000, 'MANY_LINES\n' * 100]: + editwin.write = orig_write = Mock(return_value=SENTINEL_VALUE) + squeezer = self.make_squeezer_instance(editwin) + squeezer.auto_squeeze_min_lines = 50 + + self.assertEqual(squeezer.editwin.write(text, "stdout"), None) + self.assertEqual(orig_write.call_count, 0) + self.assertEqual(len(squeezer.expandingbuttons), 1) def test_auto_squeeze(self): """Test that the auto-squeezing creates an ExpandingButton properly.""" diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 8637e8ebf2c695..841cc85c539f80 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -34,6 +34,11 @@ def _init_tk_type(): _tk_type = "cocoa" return + else: + if _idle_root is None: + _tk_type = "cocoa" + return + ws = _idle_root.tk.call('tk', 'windowingsystem') if 'x11' in ws: _tk_type = "xquartz" From 8d9a7f0b5e85879785aa15cb935069e4f5b747f8 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Tue, 9 Jan 2024 14:52:42 +0100 Subject: [PATCH 14/15] Fix copy&paste error --- Lib/idlelib/idle_test/test_squeezer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/idle_test/test_squeezer.py b/Lib/idlelib/idle_test/test_squeezer.py index 29d2ba5820fc4d..524e0afdcf144a 100644 --- a/Lib/idlelib/idle_test/test_squeezer.py +++ b/Lib/idlelib/idle_test/test_squeezer.py @@ -23,7 +23,7 @@ def get_test_tk_root(test_instance): requires('gui') root = Tk() root.withdraw() - patcher = mock.patch("idlelib.macosx._idle_root", new=root) + patcher = patch("idlelib.macosx._idle_root", new=root) patcher.start() def cleanup_root(): From bf6f348c40228dda24edec349b324ab1d13b00cd Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sat, 10 Feb 2024 11:43:44 +0100 Subject: [PATCH 15/15] review comments --- Lib/idlelib/config.py | 2 +- Lib/idlelib/pyshell.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 1acb1d69164a82..09d101a5ffe66e 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -667,7 +667,7 @@ def GetCoreKeys(self, keySetName=None): # to the key bindings an rely the default binding. # # Without this IDLE will prompt twice about closing a file with - # unsaved # changes when the user quits IDLE using the keyboard + # unsaved changes when the user quits IDLE using the keyboard # shortcutand then chooses "Cancel" the first time the dialog # appears. del keyBindings['<>'] diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 43977bf81d6058..ae09608fe9634d 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1611,7 +1611,6 @@ def main(): from idlelib.run import fix_scaling fix_scaling(root) - # start editor and/or shell windows: fixwordbreaks(root) fix_x11_paste(root) flist = PyShellFileList(root) @@ -1636,6 +1635,7 @@ def main(): root.wm_iconphoto(True, *icons) + # start editor and/or shell windows: if enable_edit: if not (cmd or script): for filename in args[:]: