[Python-checkins] bpo-40468: Factor out class ExtPage in idlelib.configdialog (GH-26618)

miss-islington webhook-mailer at python.org
Tue Jun 8 22:05:36 EDT 2021


https://github.com/python/cpython/commit/c8353239eda0d05f7facd1a19acc2b836a057807
commit: c8353239eda0d05f7facd1a19acc2b836a057807
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2021-06-08T19:05:28-07:00
summary:

bpo-40468: Factor out class ExtPage in idlelib.configdialog (GH-26618)

(cherry picked from commit 5571cabf1b3385087aba2c7c10289bba77494e08)

Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu>

files:
M Lib/idlelib/configdialog.py
M Lib/idlelib/idle_test/test_configdialog.py

diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py
index 6638c062d2549..9c0153b1a7361 100644
--- a/Lib/idlelib/configdialog.py
+++ b/Lib/idlelib/configdialog.py
@@ -112,11 +112,11 @@ def create_widgets(self):
         self.frame = frame = Frame(self, padding="5px")
         self.frame.grid(sticky="nwes")
         self.note = note = Notebook(frame)
-        self.highpage = HighPage(note)
+        self.extpage = ExtPage(note)
+        self.highpage = HighPage(note, self.extpage)
         self.fontpage = FontPage(note, self.highpage)
-        self.keyspage = KeysPage(note)
+        self.keyspage = KeysPage(note, self.extpage)
         self.genpage = GenPage(note)
-        self.extpage = self.create_page_extensions()
         note.add(self.fontpage, text='Fonts/Tabs')
         note.add(self.highpage, text='Highlights')
         note.add(self.keyspage, text=' Keys ')
@@ -244,198 +244,6 @@ def activate_config_changes(self):
         for klass in reloadables:
             klass.reload()
 
-    def create_page_extensions(self):
-        """Part of the config dialog used for configuring IDLE extensions.
-
-        This code is generic - it works for any and all IDLE extensions.
-
-        IDLE extensions save their configuration options using idleConf.
-        This code reads the current configuration using idleConf, supplies a
-        GUI interface to change the configuration values, and saves the
-        changes using idleConf.
-
-        Not all changes take effect immediately - some may require restarting IDLE.
-        This depends on each extension's implementation.
-
-        All values are treated as text, and it is up to the user to supply
-        reasonable values. The only exception to this are the 'enable*' options,
-        which are boolean, and can be toggled with a True/False button.
-
-        Methods:
-            load_extensions:
-            extension_selected: Handle selection from list.
-            create_extension_frame: Hold widgets for one extension.
-            set_extension_value: Set in userCfg['extensions'].
-            save_all_changed_extensions: Call extension page Save().
-        """
-        self.ext_defaultCfg = idleConf.defaultCfg['extensions']
-        self.ext_userCfg = idleConf.userCfg['extensions']
-        self.is_int = self.register(is_int)
-        self.load_extensions()
-        # Create widgets - a listbox shows all available extensions, with the
-        # controls for the extension selected in the listbox to the right.
-        self.extension_names = StringVar(self)
-        frame = Frame(self.note)
-        frame_ext = LabelFrame(frame, borderwidth=2, relief=GROOVE,
-                               text=' Feature Extensions ')
-        frame_ext.rowconfigure(0, weight=1)
-        frame_ext.columnconfigure(2, weight=1)
-        self.extension_list = Listbox(frame_ext, listvariable=self.extension_names,
-                                      selectmode='browse')
-        self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
-        scroll = Scrollbar(frame_ext, command=self.extension_list.yview)
-        self.extension_list.yscrollcommand=scroll.set
-        self.details_frame = LabelFrame(frame_ext, width=250, height=250)
-        self.extension_list.grid(column=0, row=0, sticky='nws')
-        scroll.grid(column=1, row=0, sticky='ns')
-        self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
-        frame_ext.configure(padding=10)
-        self.config_frame = {}
-        self.current_extension = None
-
-        self.outerframe = self                      # TEMPORARY
-        self.tabbed_page_set = self.extension_list  # TEMPORARY
-
-        # Create the frame holding controls for each extension.
-        ext_names = ''
-        for ext_name in sorted(self.extensions):
-            self.create_extension_frame(ext_name)
-            ext_names = ext_names + '{' + ext_name + '} '
-        self.extension_names.set(ext_names)
-        self.extension_list.selection_set(0)
-        self.extension_selected(None)
-
-
-        self.frame_help = HelpFrame(frame, borderwidth=2, relief=GROOVE,
-                                    text=' Help Menu Extensions ')
-        frame_ext.grid(row=0, column=0, sticky='nsew')
-        Label(frame).grid(row=1, column=0)
-        self.frame_help.grid(row=2, column=0, sticky='sew')
-
-        return frame
-
-    def load_extensions(self):
-        "Fill self.extensions with data from the default and user configs."
-        self.extensions = {}
-        for ext_name in idleConf.GetExtensions(active_only=False):
-            # Former built-in extensions are already filtered out.
-            self.extensions[ext_name] = []
-
-        for ext_name in self.extensions:
-            opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
-
-            # Bring 'enable' options to the beginning of the list.
-            enables = [opt_name for opt_name in opt_list
-                       if opt_name.startswith('enable')]
-            for opt_name in enables:
-                opt_list.remove(opt_name)
-            opt_list = enables + opt_list
-
-            for opt_name in opt_list:
-                def_str = self.ext_defaultCfg.Get(
-                        ext_name, opt_name, raw=True)
-                try:
-                    def_obj = {'True':True, 'False':False}[def_str]
-                    opt_type = 'bool'
-                except KeyError:
-                    try:
-                        def_obj = int(def_str)
-                        opt_type = 'int'
-                    except ValueError:
-                        def_obj = def_str
-                        opt_type = None
-                try:
-                    value = self.ext_userCfg.Get(
-                            ext_name, opt_name, type=opt_type, raw=True,
-                            default=def_obj)
-                except ValueError:  # Need this until .Get fixed.
-                    value = def_obj  # Bad values overwritten by entry.
-                var = StringVar(self)
-                var.set(str(value))
-
-                self.extensions[ext_name].append({'name': opt_name,
-                                                  'type': opt_type,
-                                                  'default': def_str,
-                                                  'value': value,
-                                                  'var': var,
-                                                 })
-
-    def extension_selected(self, event):
-        "Handle selection of an extension from the list."
-        newsel = self.extension_list.curselection()
-        if newsel:
-            newsel = self.extension_list.get(newsel)
-        if newsel is None or newsel != self.current_extension:
-            if self.current_extension:
-                self.details_frame.config(text='')
-                self.config_frame[self.current_extension].grid_forget()
-                self.current_extension = None
-        if newsel:
-            self.details_frame.config(text=newsel)
-            self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
-            self.current_extension = newsel
-
-    def create_extension_frame(self, ext_name):
-        """Create a frame holding the widgets to configure one extension"""
-        f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
-        self.config_frame[ext_name] = f
-        entry_area = f.interior
-        # Create an entry for each configuration option.
-        for row, opt in enumerate(self.extensions[ext_name]):
-            # Create a row with a label and entry/checkbutton.
-            label = Label(entry_area, text=opt['name'])
-            label.grid(row=row, column=0, sticky=NW)
-            var = opt['var']
-            if opt['type'] == 'bool':
-                Checkbutton(entry_area, variable=var,
-                            onvalue='True', offvalue='False', width=8
-                            ).grid(row=row, column=1, sticky=W, padx=7)
-            elif opt['type'] == 'int':
-                Entry(entry_area, textvariable=var, validate='key',
-                      validatecommand=(self.is_int, '%P'), width=10
-                      ).grid(row=row, column=1, sticky=NSEW, padx=7)
-
-            else:  # type == 'str'
-                # Limit size to fit non-expanding space with larger font.
-                Entry(entry_area, textvariable=var, width=15
-                      ).grid(row=row, column=1, sticky=NSEW, padx=7)
-        return
-
-    def set_extension_value(self, section, opt):
-        """Return True if the configuration was added or changed.
-
-        If the value is the same as the default, then remove it
-        from user config file.
-        """
-        name = opt['name']
-        default = opt['default']
-        value = opt['var'].get().strip() or default
-        opt['var'].set(value)
-        # if self.defaultCfg.has_section(section):
-        # Currently, always true; if not, indent to return.
-        if (value == default):
-            return self.ext_userCfg.RemoveOption(section, name)
-        # Set the option.
-        return self.ext_userCfg.SetOption(section, name, value)
-
-    def save_all_changed_extensions(self):
-        """Save configuration changes to the user config file.
-
-        Attributes accessed:
-            extensions
-
-        Methods:
-            set_extension_value
-        """
-        has_changes = False
-        for ext_name in self.extensions:
-            options = self.extensions[ext_name]
-            for opt in options:
-                if self.set_extension_value(ext_name, opt):
-                    has_changes = True
-        if has_changes:
-            self.ext_userCfg.Save()
-
 
 # class TabPage(Frame):  # A template for Page classes.
 #     def __init__(self, master):
@@ -695,8 +503,9 @@ def var_changed_space_num(self, *params):
 
 class HighPage(Frame):
 
-    def __init__(self, master):
+    def __init__(self, master, extpage):
         super().__init__(master)
+        self.extpage = extpage
         self.cd = master.winfo_toplevel()
         self.style = Style(master)
         self.create_page_highlight()
@@ -1347,15 +1156,16 @@ def delete_custom(self):
         self.builtin_name.set(idleConf.defaultCfg['main'].Get('Theme', 'name'))
         # User can't back out of these changes, they must be applied now.
         changes.save_all()
-        self.cd.save_all_changed_extensions()
+        self.extpage.save_all_changed_extensions()
         self.cd.activate_config_changes()
         self.set_theme_type()
 
 
 class KeysPage(Frame):
 
-    def __init__(self, master):
+    def __init__(self, master, extpage):
         super().__init__(master)
+        self.extpage = extpage
         self.cd = master.winfo_toplevel()
         self.create_page_keys()
         self.load_key_cfg()
@@ -1779,7 +1589,7 @@ def delete_custom_keys(self):
                               or idleConf.default_keys())
         # User can't back out of these changes, they must be applied now.
         changes.save_all()
-        self.cd.save_all_changed_extensions()
+        self.extpage.save_all_changed_extensions()
         self.cd.activate_config_changes()
         self.set_keys_type()
 
@@ -2094,6 +1904,201 @@ def load_shelled_cfg(self):
                 'main', 'PyShell', 'auto-squeeze-min-lines', type='int'))
 
 
+class ExtPage(Frame):
+    def __init__(self, master):
+        super().__init__(master)
+        self.ext_defaultCfg = idleConf.defaultCfg['extensions']
+        self.ext_userCfg = idleConf.userCfg['extensions']
+        self.is_int = self.register(is_int)
+        self.load_extensions()
+        self.create_page_extensions()  # Requires extension names.
+
+    def create_page_extensions(self):
+        """Configure IDLE feature extensions and help menu extensions.
+
+        List the feature extensions and a configuration box for the
+        selected extension.  Help menu extensions are in a HelpFrame.
+
+        This code reads the current configuration using idleConf,
+        supplies a GUI interface to change the configuration values,
+        and saves the changes using idleConf.
+
+        Some changes may require restarting IDLE.  This depends on each
+        extension's implementation.
+
+        All values are treated as text, and it is up to the user to
+        supply reasonable values. The only exception to this are the
+        'enable*' options, which are boolean, and can be toggled with a
+        True/False button.
+
+        Methods:
+            extension_selected: Handle selection from list.
+            create_extension_frame: Hold widgets for one extension.
+            set_extension_value: Set in userCfg['extensions'].
+            save_all_changed_extensions: Call extension page Save().
+        """
+        self.extension_names = StringVar(self)
+
+        frame_ext = LabelFrame(self, borderwidth=2, relief=GROOVE,
+                               text=' Feature Extensions ')
+        self.frame_help = HelpFrame(self, borderwidth=2, relief=GROOVE,
+                               text=' Help Menu Extensions ')
+
+        frame_ext.rowconfigure(0, weight=1)
+        frame_ext.columnconfigure(2, weight=1)
+        self.extension_list = Listbox(frame_ext, listvariable=self.extension_names,
+                                      selectmode='browse')
+        self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
+        scroll = Scrollbar(frame_ext, command=self.extension_list.yview)
+        self.extension_list.yscrollcommand=scroll.set
+        self.details_frame = LabelFrame(frame_ext, width=250, height=250)
+        self.extension_list.grid(column=0, row=0, sticky='nws')
+        scroll.grid(column=1, row=0, sticky='ns')
+        self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
+        frame_ext.configure(padding=10)
+        self.config_frame = {}
+        self.current_extension = None
+
+        self.outerframe = self                      # TEMPORARY
+        self.tabbed_page_set = self.extension_list  # TEMPORARY
+
+        # Create the frame holding controls for each extension.
+        ext_names = ''
+        for ext_name in sorted(self.extensions):
+            self.create_extension_frame(ext_name)
+            ext_names = ext_names + '{' + ext_name + '} '
+        self.extension_names.set(ext_names)
+        self.extension_list.selection_set(0)
+        self.extension_selected(None)
+
+
+        frame_ext.grid(row=0, column=0, sticky='nsew')
+        Label(self).grid(row=1, column=0)  # Spacer.  Replace with config?
+        self.frame_help.grid(row=2, column=0, sticky='sew')
+
+    def load_extensions(self):
+        "Fill self.extensions with data from the default and user configs."
+        self.extensions = {}
+        for ext_name in idleConf.GetExtensions(active_only=False):
+            # Former built-in extensions are already filtered out.
+            self.extensions[ext_name] = []
+
+        for ext_name in self.extensions:
+            opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
+
+            # Bring 'enable' options to the beginning of the list.
+            enables = [opt_name for opt_name in opt_list
+                       if opt_name.startswith('enable')]
+            for opt_name in enables:
+                opt_list.remove(opt_name)
+            opt_list = enables + opt_list
+
+            for opt_name in opt_list:
+                def_str = self.ext_defaultCfg.Get(
+                        ext_name, opt_name, raw=True)
+                try:
+                    def_obj = {'True':True, 'False':False}[def_str]
+                    opt_type = 'bool'
+                except KeyError:
+                    try:
+                        def_obj = int(def_str)
+                        opt_type = 'int'
+                    except ValueError:
+                        def_obj = def_str
+                        opt_type = None
+                try:
+                    value = self.ext_userCfg.Get(
+                            ext_name, opt_name, type=opt_type, raw=True,
+                            default=def_obj)
+                except ValueError:  # Need this until .Get fixed.
+                    value = def_obj  # Bad values overwritten by entry.
+                var = StringVar(self)
+                var.set(str(value))
+
+                self.extensions[ext_name].append({'name': opt_name,
+                                                  'type': opt_type,
+                                                  'default': def_str,
+                                                  'value': value,
+                                                  'var': var,
+                                                 })
+
+    def extension_selected(self, event):
+        "Handle selection of an extension from the list."
+        newsel = self.extension_list.curselection()
+        if newsel:
+            newsel = self.extension_list.get(newsel)
+        if newsel is None or newsel != self.current_extension:
+            if self.current_extension:
+                self.details_frame.config(text='')
+                self.config_frame[self.current_extension].grid_forget()
+                self.current_extension = None
+        if newsel:
+            self.details_frame.config(text=newsel)
+            self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
+            self.current_extension = newsel
+
+    def create_extension_frame(self, ext_name):
+        """Create a frame holding the widgets to configure one extension"""
+        f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
+        self.config_frame[ext_name] = f
+        entry_area = f.interior
+        # Create an entry for each configuration option.
+        for row, opt in enumerate(self.extensions[ext_name]):
+            # Create a row with a label and entry/checkbutton.
+            label = Label(entry_area, text=opt['name'])
+            label.grid(row=row, column=0, sticky=NW)
+            var = opt['var']
+            if opt['type'] == 'bool':
+                Checkbutton(entry_area, variable=var,
+                            onvalue='True', offvalue='False', width=8
+                            ).grid(row=row, column=1, sticky=W, padx=7)
+            elif opt['type'] == 'int':
+                Entry(entry_area, textvariable=var, validate='key',
+                      validatecommand=(self.is_int, '%P'), width=10
+                      ).grid(row=row, column=1, sticky=NSEW, padx=7)
+
+            else:  # type == 'str'
+                # Limit size to fit non-expanding space with larger font.
+                Entry(entry_area, textvariable=var, width=15
+                      ).grid(row=row, column=1, sticky=NSEW, padx=7)
+        return
+
+    def set_extension_value(self, section, opt):
+        """Return True if the configuration was added or changed.
+
+        If the value is the same as the default, then remove it
+        from user config file.
+        """
+        name = opt['name']
+        default = opt['default']
+        value = opt['var'].get().strip() or default
+        opt['var'].set(value)
+        # if self.defaultCfg.has_section(section):
+        # Currently, always true; if not, indent to return.
+        if (value == default):
+            return self.ext_userCfg.RemoveOption(section, name)
+        # Set the option.
+        return self.ext_userCfg.SetOption(section, name, value)
+
+    def save_all_changed_extensions(self):
+        """Save configuration changes to the user config file.
+
+        Attributes accessed:
+            extensions
+
+        Methods:
+            set_extension_value
+        """
+        has_changes = False
+        for ext_name in self.extensions:
+            options = self.extensions[ext_name]
+            for opt in options:
+                if self.set_extension_value(ext_name, opt):
+                    has_changes = True
+        if has_changes:
+            self.ext_userCfg.Save()
+
+
 class HelpFrame(LabelFrame):
 
     def __init__(self, master, **cfg):
diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py
index 214d1b379b55d..e01aa634473dc 100644
--- a/Lib/idlelib/idle_test/test_configdialog.py
+++ b/Lib/idlelib/idle_test/test_configdialog.py
@@ -1292,12 +1292,22 @@ def test_context(self):
         self.assertEqual(extpage, {'CodeContext': {'maxlines': '1'}})
 
 
+#unittest.skip("Nothing here yet TODO")
+class ExtPageTest(unittest.TestCase):
+    """Test that the help source list works correctly."""
+    @classmethod
+    def setUpClass(cls):
+        page = dialog.extpage
+        dialog.note.select(page)
+
+
 class HelpSourceTest(unittest.TestCase):
     """Test that the help source list works correctly."""
     @classmethod
     def setUpClass(cls):
-        dialog.note.select(dialog.extpage)
-        frame = cls.frame = dialog.frame_help
+        page = dialog.extpage
+        dialog.note.select(page)
+        frame = cls.frame = page.frame_help
         frame.set = frame.set_add_delete_state = Func()
         frame.upc = frame.update_help_changes = Func()
         frame.update()



More information about the Python-checkins mailing list