From d2f44b4eab5d4ab79e3c80082e7613455b0b5923 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Mon, 20 Nov 2017 20:14:39 -0500 Subject: [PATCH 1/5] bpo-32100: IDLE: PathBrowser does not open --- Lib/idlelib/browser.py | 6 +++--- Lib/idlelib/editor.py | 2 +- Lib/idlelib/pathbrowser.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/browser.py b/Lib/idlelib/browser.py index 79eaeb7eb45bf4..e61e72e3b387d1 100644 --- a/Lib/idlelib/browser.py +++ b/Lib/idlelib/browser.py @@ -79,9 +79,6 @@ def __init__(self, master, path, *, _htest=False, _utest=False): creating ModuleBrowserTreeItem as the rootnode for the tree and subsequently in the children. """ - global file_open - if not (_htest or _utest): - file_open = pyshell.flist.open self.master = master self.path = path self._htest = _htest @@ -95,6 +92,9 @@ def close(self, event=None): def init(self): "Create browser tkinter widgets, including the tree." + global file_open + if not (self._htest or self._utest): + file_open = pyshell.flist.open root = self.master # reset pyclbr pyclbr._modules.clear() diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 68450c921f2fad..b51c45c97e50f2 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -668,7 +668,7 @@ def open_module_browser(self, event=None): def open_path_browser(self, event=None): from idlelib import pathbrowser - pathbrowser.PathBrowser(self.flist) + pathbrowser.PathBrowser(self.root) return "break" def open_turtle_demo(self, event = None): diff --git a/Lib/idlelib/pathbrowser.py b/Lib/idlelib/pathbrowser.py index c0aa2a1590916c..c61ae0f4fb96cc 100644 --- a/Lib/idlelib/pathbrowser.py +++ b/Lib/idlelib/pathbrowser.py @@ -9,13 +9,14 @@ class PathBrowser(ModuleBrowser): - def __init__(self, flist, *, _htest=False, _utest=False): + def __init__(self, master, *, _htest=False, _utest=False): """ _htest - bool, change box location when running htest """ + self.master = master self._htest = _htest self._utest = _utest - self.init(flist) + self.init() def settitle(self): "Set window titles." @@ -100,8 +101,7 @@ def listmodules(self, allnames): def _path_browser(parent): # htest # - flist = PyShellFileList(parent) - PathBrowser(flist, _htest=True) + PathBrowser(parent, _htest=True) parent.mainloop() if __name__ == "__main__": From abc7f126e180450e8421879af3d5b03a3ebb3872 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Tue, 21 Nov 2017 08:26:22 -0500 Subject: [PATCH 2/5] Add blurb --- Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst diff --git a/Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst b/Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst new file mode 100644 index 00000000000000..ae21c46e810b26 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst @@ -0,0 +1 @@ +IDLE: Fix errors in PathBrowser. From b64e8ddffc4bc09589f7506176a742c230dfe1a7 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Tue, 21 Nov 2017 18:02:42 -0500 Subject: [PATCH 3/5] Add unit test for PathBrowser class. --- Lib/idlelib/idle_test/test_pathbrowser.py | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/Lib/idlelib/idle_test/test_pathbrowser.py b/Lib/idlelib/idle_test/test_pathbrowser.py index 813cbcc63167cc..bc3cfd86f209cf 100644 --- a/Lib/idlelib/idle_test/test_pathbrowser.py +++ b/Lib/idlelib/idle_test/test_pathbrowser.py @@ -1,11 +1,63 @@ +""" Test idlelib.pathbrowser. +""" + import unittest import os import sys +import pyclbr + import idlelib from idlelib import pathbrowser +from idlelib.tree import TreeNode +from test.support import requires +from tkinter import Tk +from idlelib.idle_test.mock_idle import Func + class PathBrowserTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = Tk() + cls.root.withdraw() + cls.pb = pathbrowser.PathBrowser(cls.root, _utest=True) + + @classmethod + def tearDownClass(cls): + cls.pb.close() + cls.root.destroy() + del cls.root, cls.pb + + def test_init(self): + pb = self.pb + eq = self.assertEqual + eq(pb.master, self.root) + eq(pyclbr._modules, {}) + self.assertIsInstance(pb.node, TreeNode) + + def test_settitle(self): + pb = self.pb + self.assertEqual(pb.top.title(), 'Path Browser') + self.assertEqual(pb.top.iconname(), 'Path Browser') + + def test_rootnode(self): + pb = self.pb + rn = pb.rootnode() + self.assertIsInstance(rn, pathbrowser.PathBrowserTreeItem) + + def test_close(self): + pb = self.pb + pb.top.destroy = Func() + pb.node.destroy = Func() + pb.close() + self.assertTrue(pb.top.destroy.called) + self.assertTrue(pb.node.destroy.called) + del pb.top.destroy, pb.node.destroy + + +class DirBrowserTreeItemTest(unittest.TestCase): + def test_DirBrowserTreeItem(self): # Issue16226 - make sure that getting a sublist works d = pathbrowser.DirBrowserTreeItem('') @@ -16,6 +68,9 @@ def test_DirBrowserTreeItem(self): self.assertEqual(d.ispackagedir(dir), True) self.assertEqual(d.ispackagedir(dir + '/Icons'), False) + +class PathBrowserTreeItemTest(unittest.TestCase): + def test_PathBrowserTreeItem(self): p = pathbrowser.PathBrowserTreeItem() self.assertEqual(p.GetText(), 'sys.path') @@ -23,5 +78,6 @@ def test_PathBrowserTreeItem(self): self.assertEqual(len(sub), len(sys.path)) self.assertEqual(type(sub[0]), pathbrowser.DirBrowserTreeItem) + if __name__ == '__main__': unittest.main(verbosity=2, exit=False) From 0a30f0db6e7748c9b2f30a8c8f5fb02ff018e3b5 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Wed, 22 Nov 2017 17:56:34 -0500 Subject: [PATCH 4/5] Fixup file_open binding and tests. --- Lib/idlelib/browser.py | 10 ++++----- Lib/idlelib/idle_test/test_browser.py | 26 +++++++++++------------ Lib/idlelib/idle_test/test_pathbrowser.py | 19 +++++++++++------ 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Lib/idlelib/browser.py b/Lib/idlelib/browser.py index e61e72e3b387d1..447dafcc515e6c 100644 --- a/Lib/idlelib/browser.py +++ b/Lib/idlelib/browser.py @@ -93,11 +93,12 @@ def close(self, event=None): def init(self): "Create browser tkinter widgets, including the tree." global file_open - if not (self._htest or self._utest): - file_open = pyshell.flist.open root = self.master - # reset pyclbr + flist = (pyshell.flist if not (self._htest or self._utest) + else pyshell.PyShellFileList(root)) + file_open = flist.open pyclbr._modules.clear() + # create top self.top = top = ListedToplevel(root) top.protocol("WM_DELETE_WINDOW", self.close) @@ -107,6 +108,7 @@ def init(self): (root.winfo_rootx(), root.winfo_rooty() + 200)) self.settitle() top.focus_set() + # create scrolled canvas theme = idleConf.CurrentTheme() background = idleConf.GetHighlight(theme, 'normal')['background'] @@ -236,8 +238,6 @@ class Nested_in_func(TreeNode): def nested_in_class(): pass def closure(): class Nested_in_closure: pass - global file_open - file_open = pyshell.PyShellFileList(parent).open ModuleBrowser(parent, file, _htest=True) if __name__ == "__main__": diff --git a/Lib/idlelib/idle_test/test_browser.py b/Lib/idlelib/idle_test/test_browser.py index 59e03c5aab3c9e..34eb332c1df434 100644 --- a/Lib/idlelib/idle_test/test_browser.py +++ b/Lib/idlelib/idle_test/test_browser.py @@ -4,17 +4,19 @@ (Higher, because should exclude 3 lines that .coveragerc won't exclude.) """ +from collections import deque import os.path -import unittest import pyclbr +from tkinter import Tk -from idlelib import browser, filelist -from idlelib.tree import TreeNode from test.support import requires +import unittest from unittest import mock -from tkinter import Tk from idlelib.idle_test.mock_idle import Func -from collections import deque + +from idlelib import browser +from idlelib import filelist +from idlelib.tree import TreeNode class ModuleBrowserTest(unittest.TestCase): @@ -29,6 +31,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.mb.close() + cls.root.update_idletasks() cls.root.destroy() del cls.root, cls.mb @@ -38,6 +41,7 @@ def test_init(self): eq(mb.path, __file__) eq(pyclbr._modules, {}) self.assertIsInstance(mb.node, TreeNode) + self.assertIsNotNone(browser.file_open) def test_settitle(self): mb = self.mb @@ -151,10 +155,9 @@ def test_getsublist(self): self.assertEqual(sub0.name, 'f0') self.assertEqual(sub1.name, 'C0(base)') - - def test_ondoubleclick(self): + @mock.patch('idlelib.browser.file_open') + def test_ondoubleclick(self, fopen): mbt = self.mbt - fopen = browser.file_open = mock.Mock() with mock.patch('os.path.exists', return_value=False): mbt.OnDoubleClick() @@ -165,8 +168,6 @@ def test_ondoubleclick(self): fopen.assert_called() fopen.called_with(fname) - del browser.file_open - class ChildBrowserTreeItemTest(unittest.TestCase): @@ -212,14 +213,13 @@ def test_getsublist(self): eq(self.cbt_F1.GetSubList(), []) - def test_ondoubleclick(self): - fopen = browser.file_open = mock.Mock() + @mock.patch('idlelib.browser.file_open') + def test_ondoubleclick(self, fopen): goto = fopen.return_value.gotoline = mock.Mock() self.cbt_F1.OnDoubleClick() fopen.assert_called() goto.assert_called() goto.assert_called_with(self.cbt_F1.obj.lineno) - del browser.file_open # Failure test would have to raise OSError or AttributeError. diff --git a/Lib/idlelib/idle_test/test_pathbrowser.py b/Lib/idlelib/idle_test/test_pathbrowser.py index bc3cfd86f209cf..74b716a3199327 100644 --- a/Lib/idlelib/idle_test/test_pathbrowser.py +++ b/Lib/idlelib/idle_test/test_pathbrowser.py @@ -1,17 +1,20 @@ """ Test idlelib.pathbrowser. """ + +import os.path +import pyclbr # for _modules +import sys # for sys.path +from tkinter import Tk + +from test.support import requires import unittest -import os -import sys -import pyclbr +from idlelib.idle_test.mock_idle import Func -import idlelib +import idlelib # for __file__ +from idlelib import browser from idlelib import pathbrowser from idlelib.tree import TreeNode -from test.support import requires -from tkinter import Tk -from idlelib.idle_test.mock_idle import Func class PathBrowserTest(unittest.TestCase): @@ -26,6 +29,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.pb.close() + cls.root.update_idletasks() cls.root.destroy() del cls.root, cls.pb @@ -35,6 +39,7 @@ def test_init(self): eq(pb.master, self.root) eq(pyclbr._modules, {}) self.assertIsInstance(pb.node, TreeNode) + self.assertIsNotNone(browser.file_open) def test_settitle(self): pb = self.pb From e0aa86d2891ea9fb798fad648eb212867d4593d3 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Wed, 22 Nov 2017 18:03:48 -0500 Subject: [PATCH 5/5] Blurb. --- Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst b/Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst index ae21c46e810b26..c5ee6736a84565 100644 --- a/Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst +++ b/Misc/NEWS.d/next/IDLE/2017-11-21-08-26-08.bpo-32100.P43qx2.rst @@ -1 +1,2 @@ -IDLE: Fix errors in PathBrowser. +IDLE: Fix old and new bugs in pathbrowser; improve tests. +Patch mostly by Cheryl Sabella.