annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/browser.py @ 69:33d812a61356

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