annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/browser.py @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
rev   line source
jpayne@68 1 """Module browser.
jpayne@68 2
jpayne@68 3 XXX TO DO:
jpayne@68 4
jpayne@68 5 - reparse when source changed (maybe just a button would be OK?)
jpayne@68 6 (or recheck on window popup)
jpayne@68 7 - add popup menu with more options (e.g. doc strings, base classes, imports)
jpayne@68 8 - add base classes to class browser tree
jpayne@68 9 - finish removing limitation to x.py files (ModuleBrowserTreeItem)
jpayne@68 10 """
jpayne@68 11
jpayne@68 12 import os
jpayne@68 13 import pyclbr
jpayne@68 14 import sys
jpayne@68 15
jpayne@68 16 from idlelib.config import idleConf
jpayne@68 17 from idlelib import pyshell
jpayne@68 18 from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas
jpayne@68 19 from idlelib.window import ListedToplevel
jpayne@68 20
jpayne@68 21
jpayne@68 22 file_open = None # Method...Item and Class...Item use this.
jpayne@68 23 # Normally pyshell.flist.open, but there is no pyshell.flist for htest.
jpayne@68 24
jpayne@68 25
jpayne@68 26 def transform_children(child_dict, modname=None):
jpayne@68 27 """Transform a child dictionary to an ordered sequence of objects.
jpayne@68 28
jpayne@68 29 The dictionary maps names to pyclbr information objects.
jpayne@68 30 Filter out imported objects.
jpayne@68 31 Augment class names with bases.
jpayne@68 32 The insertion order of the dictionary is assumed to have been in line
jpayne@68 33 number order, so sorting is not necessary.
jpayne@68 34
jpayne@68 35 The current tree only calls this once per child_dict as it saves
jpayne@68 36 TreeItems once created. A future tree and tests might violate this,
jpayne@68 37 so a check prevents multiple in-place augmentations.
jpayne@68 38 """
jpayne@68 39 obs = [] # Use list since values should already be sorted.
jpayne@68 40 for key, obj in child_dict.items():
jpayne@68 41 if modname is None or obj.module == modname:
jpayne@68 42 if hasattr(obj, 'super') and obj.super and obj.name == key:
jpayne@68 43 # If obj.name != key, it has already been suffixed.
jpayne@68 44 supers = []
jpayne@68 45 for sup in obj.super:
jpayne@68 46 if type(sup) is type(''):
jpayne@68 47 sname = sup
jpayne@68 48 else:
jpayne@68 49 sname = sup.name
jpayne@68 50 if sup.module != obj.module:
jpayne@68 51 sname = f'{sup.module}.{sname}'
jpayne@68 52 supers.append(sname)
jpayne@68 53 obj.name += '({})'.format(', '.join(supers))
jpayne@68 54 obs.append(obj)
jpayne@68 55 return obs
jpayne@68 56
jpayne@68 57
jpayne@68 58 class ModuleBrowser:
jpayne@68 59 """Browse module classes and functions in IDLE.
jpayne@68 60 """
jpayne@68 61 # This class is also the base class for pathbrowser.PathBrowser.
jpayne@68 62 # Init and close are inherited, other methods are overridden.
jpayne@68 63 # PathBrowser.__init__ does not call __init__ below.
jpayne@68 64
jpayne@68 65 def __init__(self, master, path, *, _htest=False, _utest=False):
jpayne@68 66 """Create a window for browsing a module's structure.
jpayne@68 67
jpayne@68 68 Args:
jpayne@68 69 master: parent for widgets.
jpayne@68 70 path: full path of file to browse.
jpayne@68 71 _htest - bool; change box location when running htest.
jpayne@68 72 -utest - bool; suppress contents when running unittest.
jpayne@68 73
jpayne@68 74 Global variables:
jpayne@68 75 file_open: Function used for opening a file.
jpayne@68 76
jpayne@68 77 Instance variables:
jpayne@68 78 name: Module name.
jpayne@68 79 file: Full path and module with .py extension. Used in
jpayne@68 80 creating ModuleBrowserTreeItem as the rootnode for
jpayne@68 81 the tree and subsequently in the children.
jpayne@68 82 """
jpayne@68 83 self.master = master
jpayne@68 84 self.path = path
jpayne@68 85 self._htest = _htest
jpayne@68 86 self._utest = _utest
jpayne@68 87 self.init()
jpayne@68 88
jpayne@68 89 def close(self, event=None):
jpayne@68 90 "Dismiss the window and the tree nodes."
jpayne@68 91 self.top.destroy()
jpayne@68 92 self.node.destroy()
jpayne@68 93
jpayne@68 94 def init(self):
jpayne@68 95 "Create browser tkinter widgets, including the tree."
jpayne@68 96 global file_open
jpayne@68 97 root = self.master
jpayne@68 98 flist = (pyshell.flist if not (self._htest or self._utest)
jpayne@68 99 else pyshell.PyShellFileList(root))
jpayne@68 100 file_open = flist.open
jpayne@68 101 pyclbr._modules.clear()
jpayne@68 102
jpayne@68 103 # create top
jpayne@68 104 self.top = top = ListedToplevel(root)
jpayne@68 105 top.protocol("WM_DELETE_WINDOW", self.close)
jpayne@68 106 top.bind("<Escape>", self.close)
jpayne@68 107 if self._htest: # place dialog below parent if running htest
jpayne@68 108 top.geometry("+%d+%d" %
jpayne@68 109 (root.winfo_rootx(), root.winfo_rooty() + 200))
jpayne@68 110 self.settitle()
jpayne@68 111 top.focus_set()
jpayne@68 112
jpayne@68 113 # create scrolled canvas
jpayne@68 114 theme = idleConf.CurrentTheme()
jpayne@68 115 background = idleConf.GetHighlight(theme, 'normal')['background']
jpayne@68 116 sc = ScrolledCanvas(top, bg=background, highlightthickness=0,
jpayne@68 117 takefocus=1)
jpayne@68 118 sc.frame.pack(expand=1, fill="both")
jpayne@68 119 item = self.rootnode()
jpayne@68 120 self.node = node = TreeNode(sc.canvas, None, item)
jpayne@68 121 if not self._utest:
jpayne@68 122 node.update()
jpayne@68 123 node.expand()
jpayne@68 124
jpayne@68 125 def settitle(self):
jpayne@68 126 "Set the window title."
jpayne@68 127 self.top.wm_title("Module Browser - " + os.path.basename(self.path))
jpayne@68 128 self.top.wm_iconname("Module Browser")
jpayne@68 129
jpayne@68 130 def rootnode(self):
jpayne@68 131 "Return a ModuleBrowserTreeItem as the root of the tree."
jpayne@68 132 return ModuleBrowserTreeItem(self.path)
jpayne@68 133
jpayne@68 134
jpayne@68 135 class ModuleBrowserTreeItem(TreeItem):
jpayne@68 136 """Browser tree for Python module.
jpayne@68 137
jpayne@68 138 Uses TreeItem as the basis for the structure of the tree.
jpayne@68 139 Used by both browsers.
jpayne@68 140 """
jpayne@68 141
jpayne@68 142 def __init__(self, file):
jpayne@68 143 """Create a TreeItem for the file.
jpayne@68 144
jpayne@68 145 Args:
jpayne@68 146 file: Full path and module name.
jpayne@68 147 """
jpayne@68 148 self.file = file
jpayne@68 149
jpayne@68 150 def GetText(self):
jpayne@68 151 "Return the module name as the text string to display."
jpayne@68 152 return os.path.basename(self.file)
jpayne@68 153
jpayne@68 154 def GetIconName(self):
jpayne@68 155 "Return the name of the icon to display."
jpayne@68 156 return "python"
jpayne@68 157
jpayne@68 158 def GetSubList(self):
jpayne@68 159 "Return ChildBrowserTreeItems for children."
jpayne@68 160 return [ChildBrowserTreeItem(obj) for obj in self.listchildren()]
jpayne@68 161
jpayne@68 162 def OnDoubleClick(self):
jpayne@68 163 "Open a module in an editor window when double clicked."
jpayne@68 164 if os.path.normcase(self.file[-3:]) != ".py":
jpayne@68 165 return
jpayne@68 166 if not os.path.exists(self.file):
jpayne@68 167 return
jpayne@68 168 file_open(self.file)
jpayne@68 169
jpayne@68 170 def IsExpandable(self):
jpayne@68 171 "Return True if Python (.py) file."
jpayne@68 172 return os.path.normcase(self.file[-3:]) == ".py"
jpayne@68 173
jpayne@68 174 def listchildren(self):
jpayne@68 175 "Return sequenced classes and functions in the module."
jpayne@68 176 dir, base = os.path.split(self.file)
jpayne@68 177 name, ext = os.path.splitext(base)
jpayne@68 178 if os.path.normcase(ext) != ".py":
jpayne@68 179 return []
jpayne@68 180 try:
jpayne@68 181 tree = pyclbr.readmodule_ex(name, [dir] + sys.path)
jpayne@68 182 except ImportError:
jpayne@68 183 return []
jpayne@68 184 return transform_children(tree, name)
jpayne@68 185
jpayne@68 186
jpayne@68 187 class ChildBrowserTreeItem(TreeItem):
jpayne@68 188 """Browser tree for child nodes within the module.
jpayne@68 189
jpayne@68 190 Uses TreeItem as the basis for the structure of the tree.
jpayne@68 191 """
jpayne@68 192
jpayne@68 193 def __init__(self, obj):
jpayne@68 194 "Create a TreeItem for a pyclbr class/function object."
jpayne@68 195 self.obj = obj
jpayne@68 196 self.name = obj.name
jpayne@68 197 self.isfunction = isinstance(obj, pyclbr.Function)
jpayne@68 198
jpayne@68 199 def GetText(self):
jpayne@68 200 "Return the name of the function/class to display."
jpayne@68 201 name = self.name
jpayne@68 202 if self.isfunction:
jpayne@68 203 return "def " + name + "(...)"
jpayne@68 204 else:
jpayne@68 205 return "class " + name
jpayne@68 206
jpayne@68 207 def GetIconName(self):
jpayne@68 208 "Return the name of the icon to display."
jpayne@68 209 if self.isfunction:
jpayne@68 210 return "python"
jpayne@68 211 else:
jpayne@68 212 return "folder"
jpayne@68 213
jpayne@68 214 def IsExpandable(self):
jpayne@68 215 "Return True if self.obj has nested objects."
jpayne@68 216 return self.obj.children != {}
jpayne@68 217
jpayne@68 218 def GetSubList(self):
jpayne@68 219 "Return ChildBrowserTreeItems for children."
jpayne@68 220 return [ChildBrowserTreeItem(obj)
jpayne@68 221 for obj in transform_children(self.obj.children)]
jpayne@68 222
jpayne@68 223 def OnDoubleClick(self):
jpayne@68 224 "Open module with file_open and position to lineno."
jpayne@68 225 try:
jpayne@68 226 edit = file_open(self.obj.file)
jpayne@68 227 edit.gotoline(self.obj.lineno)
jpayne@68 228 except (OSError, AttributeError):
jpayne@68 229 pass
jpayne@68 230
jpayne@68 231
jpayne@68 232 def _module_browser(parent): # htest #
jpayne@68 233 if len(sys.argv) > 1: # If pass file on command line.
jpayne@68 234 file = sys.argv[1]
jpayne@68 235 else:
jpayne@68 236 file = __file__
jpayne@68 237 # Add nested objects for htest.
jpayne@68 238 class Nested_in_func(TreeNode):
jpayne@68 239 def nested_in_class(): pass
jpayne@68 240 def closure():
jpayne@68 241 class Nested_in_closure: pass
jpayne@68 242 ModuleBrowser(parent, file, _htest=True)
jpayne@68 243
jpayne@68 244 if __name__ == "__main__":
jpayne@68 245 if len(sys.argv) == 1: # If pass file on command line, unittest fails.
jpayne@68 246 from unittest import main
jpayne@68 247 main('idlelib.idle_test.test_browser', verbosity=2, exit=False)
jpayne@68 248 from idlelib.idle_test.htest import run
jpayne@68 249 run(_module_browser)