From b81e40e38b3d5214df41c2e7c1cf6a98d7d13a62 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Fri, 18 Jan 2019 13:33:50 -0500 Subject: [PATCH 1/3] Convert menudefs to dictionary --- Lib/idlelib/editor.py | 10 +++--- Lib/idlelib/idle_test/test_mainmenu.py | 2 +- Lib/idlelib/macosx.py | 22 +++++++------- Lib/idlelib/mainmenu.py | 42 +++++++++++++------------- Lib/idlelib/zzdummy.py | 8 ++--- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index e05b52a96dcc61..cc8e890d1b26b1 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -818,11 +818,11 @@ def ApplyKeybindings(self): self.apply_bindings(xkeydefs) #update menu accelerators menuEventDict = {} - for menu in self.mainmenu.menudefs: - menuEventDict[menu[0]] = {} - for item in menu[1]: + for menu, items in self.mainmenu.menudefs.items(): + menuEventDict[menu] = {} + for item in items: if item: - menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] + menuEventDict[menu][prepstr(item[0])[1]] = item[1] for menubarItem in self.menudict: menu = self.menudict[menubarItem] end = menu.index(END) @@ -1117,7 +1117,7 @@ def fill_menus(self, menudefs=None, keydefs=None): keydefs = self.mainmenu.default_keydefs menudict = self.menudict text = self.text - for mname, entrylist in menudefs: + for mname, entrylist in menudefs.items(): menu = menudict.get(mname) if not menu: continue diff --git a/Lib/idlelib/idle_test/test_mainmenu.py b/Lib/idlelib/idle_test/test_mainmenu.py index 7ec0368371c7df..147355d51a1868 100644 --- a/Lib/idlelib/idle_test/test_mainmenu.py +++ b/Lib/idlelib/idle_test/test_mainmenu.py @@ -8,7 +8,7 @@ class MainMenuTest(unittest.TestCase): def test_menudefs(self): - actual = [item[0] for item in mainmenu.menudefs] + actual = list(mainmenu.menudefs.keys()) expect = ['file', 'edit', 'format', 'run', 'shell', 'debug', 'options', 'window', 'help'] self.assertEqual(actual, expect) diff --git a/Lib/idlelib/macosx.py b/Lib/idlelib/macosx.py index 9be4ed2ec411d5..c83872c6f3bad8 100644 --- a/Lib/idlelib/macosx.py +++ b/Lib/idlelib/macosx.py @@ -165,20 +165,20 @@ def overrideRootMenu(root, flist): from idlelib import mainmenu from idlelib import window - closeItem = mainmenu.menudefs[0][1][-2] + closeItem = mainmenu.menudefs['file'][-2] # Remove the last 3 items of the file menu: a separator, close window and # quit. Close window will be reinserted just above the save item, where # it should be according to the HIG. Quit is in the application menu. - del mainmenu.menudefs[0][1][-3:] - mainmenu.menudefs[0][1].insert(6, closeItem) + del mainmenu.menudefs['file'][-3:] + mainmenu.menudefs['file'].insert(6, closeItem) # Remove the 'About' entry from the help menu, it is in the application # menu - del mainmenu.menudefs[-1][1][0:2] + del mainmenu.menudefs['help'][0:2] # Remove the 'Configure Idle' entry from the options menu, it is in the # application menu as 'Preferences' - del mainmenu.menudefs[-2][1][0] + del mainmenu.menudefs['options'][0] menubar = Menu(root) root.configure(menu=menubar) menudict = {} @@ -236,18 +236,18 @@ def help_dialog(event=None): menudict['application'] = menu = Menu(menubar, name='apple', tearoff=0) menubar.add_cascade(label='IDLE', menu=menu) - mainmenu.menudefs.insert(0, - ('application', [ - ('About IDLE', '<>'), - None, - ])) + appmenu = {'application': [ + ('About IDLE', '<>'), + None, + ]} + mainmenu.menudefs = {**appmenu, **mainmenu.menudefs} if isCocoaTk(): # replace default About dialog with About IDLE one root.createcommand('tkAboutDialog', about_dialog) # replace default "Help" item in Help menu root.createcommand('::tk::mac::ShowHelp', help_dialog) # remove redundant "IDLE Help" from menu - del mainmenu.menudefs[-1][1][0] + del mainmenu.menudefs['help'][0] def fixb2context(root): '''Removed bad AquaTk Button-2 (right) and Paste bindings. diff --git a/Lib/idlelib/mainmenu.py b/Lib/idlelib/mainmenu.py index f834220fc2bb75..b2d84f09cb919a 100644 --- a/Lib/idlelib/mainmenu.py +++ b/Lib/idlelib/mainmenu.py @@ -19,9 +19,9 @@ # without altering overrideRootMenu() as well. # TODO: Make this more robust -menudefs = [ +menudefs = { # underscore prefixes character to underscore - ('file', [ + 'file': [ ('_New File', '<>'), ('_Open...', '<>'), ('Open _Module...', '<>'), @@ -36,9 +36,9 @@ None, ('_Close', '<>'), ('E_xit', '<>'), - ]), + ], - ('edit', [ + 'edit': [ ('_Undo', '<>'), ('_Redo', '<>'), None, @@ -57,9 +57,9 @@ ('E_xpand Word', '<>'), ('Show C_all Tip', '<>'), ('Show Surrounding P_arens', '<>'), - ]), + ], - ('format', [ + 'format': [ ('_Indent Region', '<>'), ('_Dedent Region', '<>'), ('Comment _Out Region', '<>'), @@ -70,15 +70,15 @@ ('New Indent Width', '<>'), ('F_ormat Paragraph', '<>'), ('S_trip Trailing Whitespace', '<>'), - ]), + ], - ('run', [ + 'run': [ ('Python Shell', '<>'), ('C_heck Module', '<>'), ('R_un Module', '<>'), - ]), + ], - ('shell', [ + 'shell': [ ('_View Last Restart', '<>'), ('_Restart Shell', '<>'), None, @@ -86,35 +86,35 @@ ('_Next History', '<>'), None, ('_Interrupt Execution', '<>'), - ]), + ], - ('debug', [ + 'debug': [ ('_Go to File/Line', '<>'), ('!_Debugger', '<>'), ('_Stack Viewer', '<>'), ('!_Auto-open Stack Viewer', '<>'), - ]), + ], - ('options', [ + 'options': [ ('Configure _IDLE', '<>'), None, ('Show _Code Context', '<>'), ('Zoom Height', '<>'), - ]), + ], - ('window', [ - ]), + 'window': [ + ], - ('help', [ + 'help': [ ('_About IDLE', '<>'), None, ('_IDLE Help', '<>'), ('Python _Docs', '<>'), - ]), -] + ], +} if find_spec('turtledemo'): - menudefs[-1][1].append(('Turtle Demo', '<>')) + menudefs['help'].append(('Turtle Demo', '<>')) default_keydefs = idleConf.GetCurrentKeySet() diff --git a/Lib/idlelib/zzdummy.py b/Lib/idlelib/zzdummy.py index 8084499646653d..dd66aa5f1be9ad 100644 --- a/Lib/idlelib/zzdummy.py +++ b/Lib/idlelib/zzdummy.py @@ -7,12 +7,12 @@ class ZzDummy: -## menudefs = [ -## ('format', [ +## menudefs = { +## 'format': [ ## ('Z in', '<>'), ## ('Z out', '<>'), -## ] ) -## ] +## ] +## } def __init__(self, editwin): self.text = editwin.text From 4607bd489eeb466431c6fb90499e1deff92cfb57 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Fri, 18 Jan 2019 16:13:57 -0500 Subject: [PATCH 2/3] zzdummy whitespace --- Lib/idlelib/zzdummy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/zzdummy.py b/Lib/idlelib/zzdummy.py index dd66aa5f1be9ad..5d4aa553195fe6 100644 --- a/Lib/idlelib/zzdummy.py +++ b/Lib/idlelib/zzdummy.py @@ -11,7 +11,7 @@ class ZzDummy: ## 'format': [ ## ('Z in', '<>'), ## ('Z out', '<>'), -## ] +## ] ## } def __init__(self, editwin): From ddd21eedeb97cf1ee1b9970545bdd834cc539025 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Sun, 20 Jan 2019 13:30:01 -0500 Subject: [PATCH 3/3] Convert menudefs list to dictonary and add tests. * 3rd party extensions may define menudefs using the old list format, so, if it's a list, convert it to a dictionary. * Add tests for fill_menus. --- Lib/idlelib/editor.py | 36 ++++++++- Lib/idlelib/idle_test/test_editor.py | 107 ++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index cc8e890d1b26b1..01133c43bf8548 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1107,12 +1107,42 @@ def apply_bindings(self, keydefs=None): text.event_add(event, *keylist) def fill_menus(self, menudefs=None, keydefs=None): - """Add appropriate entries to the menus and submenus - - Menus that are absent or None in self.menudict are ignored. + """Add appropriate entries to the menus and submenus. + + The default menudefs and keydefs are loaded from idlelib.mainmenu. + Menus that are absent or None in self.menudict are ignored. The + default menu type created for submenus from menudefs is `command`. + A submenu item of None results in a `separator` menu type. + A submenu name beginning with ! represents a `checkbutton` type. + + The menus are stored in self.menudict. + + Args: + menudefs: Menu and submenu names, underlines (shortcuts), + and events which is a dictionary of the form: + {menu1: [(submenu1a, '<>'), + (submenu1b, '<>'), ...], + menu2: [(submenu2a, '<>'), + (submenu2b, '<>'), ...], + } + Alternate format (may have been used in extensions): + [(menu1, [(submenu1a, '<>'), + (submenu1b, '<>'), ...]), + (menu2, [(submenu2a, '<>'), + (submenu2b, '<>'), ...]), + ] + keydefs: Virtual events and keybinding definitions. Used for + the 'accelerator' text on the menu. Stored as a + dictionary of + {'<>': ['', ''],} """ if menudefs is None: menudefs = self.mainmenu.menudefs + # menudefs was changed from a list of tuples to a dictionary. + # This conversion is needed for backward-compatibility for + # existing extensions that use the list format. + if isinstance(menudefs, list): + menudefs = dict(menudefs) if keydefs is None: keydefs = self.mainmenu.default_keydefs menudict = self.menudict diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 12bc8473668334..d203b111f97e64 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -2,8 +2,10 @@ from idlelib import editor import unittest +from unittest import mock from test.support import requires -from tkinter import Tk +import tkinter as tk +from functools import partial Editor = editor.EditorWindow @@ -13,7 +15,7 @@ class EditorWindowTest(unittest.TestCase): @classmethod def setUpClass(cls): requires('gui') - cls.root = Tk() + cls.root = tk.Tk() cls.root.withdraw() @classmethod @@ -42,5 +44,106 @@ class dummy(): self.assertEqual(func(dummy, inp), out) +class MenubarTest(unittest.TestCase): + """Test functions involved with creating the menubar.""" + + @classmethod + def setUpClass(cls): + requires('gui') + root = cls.root = tk.Tk() + cls.root.withdraw() + # Test the functions called during the __init__ for + # EditorWindow that create the menubar and submenus. + # The class is mocked in order to prevent the functions + # from being called automatically. + w = cls.mock_editwin = mock.Mock(editor.EditorWindow) + w.menubar = tk.Menu(root, tearoff=False) + w.text = tk.Text(root) + w.tkinter_vars = {} + + @classmethod + def tearDownClass(cls): + w = cls.mock_editwin + w.text.destroy() + w.menubar.destroy() + del w.menubar, w.text, w + cls.root.update_idletasks() + for id in cls.root.tk.call('after', 'info'): + cls.root.after_cancel(id) + cls.root.destroy() + del cls.root + + def test_fill_menus(self): + eq = self.assertEqual + ed = editor.EditorWindow + w = self.mock_editwin + # Call real functions instead of mock. + fm = partial(editor.EditorWindow.fill_menus, w) + w.get_var_obj = ed.get_var_obj.__get__(w) + + # Initialize top level menubar. + w.menudict = {} + edit = w.menudict['edit'] = tk.Menu(w.menubar, name='edit', tearoff=False) + win = w.menudict['windows'] = tk.Menu(w.menubar, name='windows', tearoff=False) + form = w.menudict['format'] = tk.Menu(w.menubar, name='format', tearoff=False) + + # Submenus. + dict_menudefs = {'edit': [('_New', '<>'), + None, + ('!Deb_ug', '<>')], + 'shell': [('_View', '<>'), ], + 'windows': [('Zoom Height', '<>')], + } + list_menudefs = [('edit', [('_New', '<>'), + None, + ('!Deb_ug', '<>')]), + ('shell', [('_View', '<>'), ]), + ('windows', [('Zoom Height', '<>')]), + ] + keydefs = {'<>': ['']} + for menudefs in (dict_menudefs, list_menudefs): + with self.subTest(menudefs=menudefs): + fm(menudefs, keydefs) + + eq(edit.index('end'), 2) + eq(edit.type(0), tk.COMMAND) + eq(edit.entrycget(0, 'label'), 'New') + eq(edit.entrycget(0, 'underline'), 0) + self.assertIsNotNone(edit.entrycget(0, 'command')) + with self.assertRaises(tk.TclError): + self.assertIsNone(edit.entrycget(0, 'var')) + + eq(edit.type(1), tk.SEPARATOR) + with self.assertRaises(tk.TclError): + self.assertIsNone(edit.entrycget(1, 'label')) + + eq(edit.type(2), tk.CHECKBUTTON) + # Strip !. + eq(edit.entrycget(2, 'label'), 'Debug') + # Check that underline ignores !. + eq(edit.entrycget(2, 'underline'), 3) + self.assertIsNotNone(edit.entrycget(2, 'var')) + self.assertIn('<>', w.tkinter_vars) + + eq(win.index('end'), 0) + eq(win.entrycget(0, 'underline'), -1) + eq(win.entrycget(0, 'accelerator'), 'Alt+9') + + eq(form.index('end'), None) + self.assertNotIn('shell', w.menudict) + + # Cleanup menus by deleting all menu items. + edit.delete(0, 2) + win.delete(0) + form.delete(0) + + # Test defaults. + w.mainmenu.menudefs = ed.mainmenu.menudefs + w.mainmenu.default_keydefs = ed.mainmenu.default_keydefs + fm() + eq(form.index('end'), 9) # Default Format menu has 10 items. + self.assertNotIn('run', w.menudict) + + if __name__ == '__main__': unittest.main(verbosity=2) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy