From 43abd598ee2eb9f5983633701f544371b04fbbf9 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Sat, 8 Jul 2017 19:58:38 -0400 Subject: [PATCH 1/4] bpo-30881: IDLE: add docstrings to browser.py --- Lib/idlelib/browser.py | 95 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/browser.py b/Lib/idlelib/browser.py index 73c251e76d3cce..6b36f45720341e 100644 --- a/Lib/idlelib/browser.py +++ b/Lib/idlelib/browser.py @@ -23,12 +23,28 @@ # Normally pyshell.flist.open, but there is no pyshell.flist for htest. class ClassBrowser: + """Browse module classes and functions in IDLE. + """ def __init__(self, flist, name, path, _htest=False): # XXX This API should change, if the file doesn't end in ".py" # XXX the code here is bogus! - """ - _htest - bool, change box when location running htest. + """Create a window for browsing a module's structure. + + Args: + flist: filelist.FileList instance used as the root for the window. + name: Python module to parse. + path: Module search path. + _htest - bool, change box when location running htest. + + Global variables: + file_open: Function used for opening a file. + + Instance variables: + name: Module name. + file: Full path and module with .py extension. Used in + creating ModuleBrowserTreeItem as the rootnode for + the tree and subsequently in the children. """ global file_open if not _htest: @@ -39,10 +55,12 @@ def __init__(self, flist, name, path, _htest=False): self.init(flist) def close(self, event=None): + "Dismiss the window and the tree nodes." self.top.destroy() self.node.destroy() def init(self, flist): + """Create browser tkinter widgets, including the tree.""" self.flist = flist # reset pyclbr pyclbr._modules.clear() @@ -66,24 +84,42 @@ def init(self, flist): node.expand() def settitle(self): + "Set the window title." self.top.wm_title("Class Browser - " + self.name) self.top.wm_iconname("Class Browser") def rootnode(self): + "Return a ModuleBrowserTreeItem as the root of the tree." return ModuleBrowserTreeItem(self.file) class ModuleBrowserTreeItem(TreeItem): + """Browser tree for Python module. + + Uses TreeItem as the basis for the structure of the tree. + """ def __init__(self, file): + """Create a TreeItem for the file. + + Args: + file: Full path and module name. + """ self.file = file def GetText(self): + "Return the module name as the text string to display." return os.path.basename(self.file) def GetIconName(self): + "Return the name of the icon to display." return "python" def GetSubList(self): + """Return the list of ClassBrowserTreeItem items. + + Each item returned from listclasses is the first level of + classes/functions within the module. + """ sublist = [] for name in self.listclasses(): item = ClassBrowserTreeItem(name, self.classes, self.file) @@ -91,6 +127,7 @@ def GetSubList(self): return sublist def OnDoubleClick(self): + "Open a module in an editor window when double clicked." if os.path.normcase(self.file[-3:]) != ".py": return if not os.path.exists(self.file): @@ -98,9 +135,20 @@ def OnDoubleClick(self): pyshell.flist.open(self.file) def IsExpandable(self): + "Return True if Python (.py) file." return os.path.normcase(self.file[-3:]) == ".py" def listclasses(self): + """Return list of classes and functions in the module. + + The dictionary output from pyclbr is re-written as a + list of tuples in the form (lineno, name) and + then sorted so that the classes and functions are + processed in line number order. The returned list only + contains the name and not the line number. An instance + variable self.classes contains the pyclbr dictionary values, + which are instances of Class and Function. + """ dir, file = os.path.split(self.file) name, ext = os.path.splitext(file) if os.path.normcase(ext) != ".py": @@ -134,9 +182,25 @@ def listclasses(self): return list class ClassBrowserTreeItem(TreeItem): + """Browser tree for classes within a module. + + Uses TreeItem as the basis for the structure of the tree. + """ def __init__(self, name, classes, file): + """Create a TreeItem for the class/function. + + Args: + name: Name of the class/function. + classes: Dictonary of Class/Function instances from pyclbr. + file: Full path and module name. + + Instance variables: + self.cl: Class/Function instance for the class/function name. + self.isfunction: True if self.cl is a Function. + """ self.name = name + # XXX - does classes need to be an instance variable? self.classes = classes self.file = file try: @@ -146,25 +210,33 @@ def __init__(self, name, classes, file): self.isfunction = isinstance(self.cl, pyclbr.Function) def GetText(self): + "Return the name of the function/class to display." if self.isfunction: return "def " + self.name + "(...)" else: return "class " + self.name def GetIconName(self): + "Return the name of the icon to display." if self.isfunction: return "python" else: return "folder" def IsExpandable(self): + "Return True if this class has methods." if self.cl: try: return not not self.cl.methods except AttributeError: return False + return None def GetSubList(self): + """Return Class methods as a list of MethodBrowserTreeItem items. + + Each item is a method within the class. + """ if not self.cl: return [] sublist = [] @@ -174,6 +246,7 @@ def GetSubList(self): return sublist def OnDoubleClick(self): + "Open module with file_open and position to lineno, if it exists." if not os.path.exists(self.file): return edit = file_open(self.file) @@ -182,6 +255,7 @@ def OnDoubleClick(self): edit.gotoline(lineno) def listmethods(self): + "Return list of methods within a class sorted by lineno." if not self.cl: return [] items = [] @@ -194,22 +268,37 @@ def listmethods(self): return list class MethodBrowserTreeItem(TreeItem): + """Browser tree for methods within a class. + + Uses TreeItem as the basis for the structure of the tree. + """ def __init__(self, name, cl, file): + """Create a TreeItem for the methods. + + Args: + name: Name of the class/function. + cl: pyclbr.Class instance for name. + file: Full path and module name. + """ self.name = name self.cl = cl self.file = file def GetText(self): + "Return the method name to display." return "def " + self.name + "(...)" def GetIconName(self): + "Return the name of the icon to display." return "python" # XXX def IsExpandable(self): - return 0 + "Return False as there are no tree items after methods." + return False def OnDoubleClick(self): + "Open module with file_open and position at the method start." if not os.path.exists(self.file): return edit = file_open(self.file) From 7ba906e0d8c8b28203ed21e92cd85cb12c1a5394 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Mon, 10 Jul 2017 07:39:30 -0400 Subject: [PATCH 2/4] Fix comment style --- Lib/idlelib/browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/browser.py b/Lib/idlelib/browser.py index 6b36f45720341e..2c58365151ff38 100644 --- a/Lib/idlelib/browser.py +++ b/Lib/idlelib/browser.py @@ -60,7 +60,7 @@ def close(self, event=None): self.node.destroy() def init(self, flist): - """Create browser tkinter widgets, including the tree.""" + "Create browser tkinter widgets, including the tree." self.flist = flist # reset pyclbr pyclbr._modules.clear() From cf075d5466b59a7e48fa8a661a1dfa33c1f228b1 Mon Sep 17 00:00:00 2001 From: terryjreedy Date: Tue, 11 Jul 2017 02:12:11 -0400 Subject: [PATCH 3/4] Update browser.py Fix comment and remove empty comment. --- Lib/idlelib/browser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/browser.py b/Lib/idlelib/browser.py index 2c58365151ff38..4cf4744fb0a8ed 100644 --- a/Lib/idlelib/browser.py +++ b/Lib/idlelib/browser.py @@ -200,7 +200,7 @@ def __init__(self, name, classes, file): self.isfunction: True if self.cl is a Function. """ self.name = name - # XXX - does classes need to be an instance variable? + # XXX - Does classes need to be an instance variable? self.classes = classes self.file = file try: @@ -291,7 +291,7 @@ def GetText(self): def GetIconName(self): "Return the name of the icon to display." - return "python" # XXX + return "python" def IsExpandable(self): "Return False as there are no tree items after methods." From db754396ba4821df4c13c7be94bf29cb7db5c6e8 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 11 Jul 2017 02:22:20 -0400 Subject: [PATCH 4/4] News blurb --- Misc/NEWS.d/next/IDLE/2017-07-11-02-21-42.bpo-30881.4KAq_9.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/IDLE/2017-07-11-02-21-42.bpo-30881.4KAq_9.rst diff --git a/Misc/NEWS.d/next/IDLE/2017-07-11-02-21-42.bpo-30881.4KAq_9.rst b/Misc/NEWS.d/next/IDLE/2017-07-11-02-21-42.bpo-30881.4KAq_9.rst new file mode 100644 index 00000000000000..4e4e0e69a01e2e --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2017-07-11-02-21-42.bpo-30881.4KAq_9.rst @@ -0,0 +1 @@ +IDLE: Add docstrings to browser.py. Patch by Cheryl Sabella.