From 223a22b6ababadefa831c634f3094e24d0e36cbe Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 22 Jun 2013 18:26:38 -0400 Subject: #18151, part 2: Silence debug build resource warning for each file opened by 'Find in files' by replacing 'open with implicit close' by 'with open' in GrepDialog method grep_it. Streamline code with enumerate(), direct file iteration, and output tweak. Add test for this method, including output format. --- Lib/idlelib/GrepDialog.py | 42 +++++++++---------- Lib/idlelib/idle_test/test_grep.py | 82 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 Lib/idlelib/idle_test/test_grep.py diff --git a/Lib/idlelib/GrepDialog.py b/Lib/idlelib/GrepDialog.py index e40e546..c8b703c 100644 --- a/Lib/idlelib/GrepDialog.py +++ b/Lib/idlelib/GrepDialog.py @@ -81,31 +81,19 @@ class GrepDialog(SearchDialogBase): hits = 0 for fn in list: try: - f = open(fn) - except IOError, msg: + with open(fn) as f: + for lineno, line in enumerate(f, 1): + if line[-1:] == '\n': + line = line[:-1] + if prog.search(line): + sys.stdout.write("%s: %s: %s\n" % + (fn, lineno, line)) + hits += 1 + except IOError as msg: print msg - continue - lineno = 0 - while 1: - block = f.readlines(100000) - if not block: - break - for line in block: - lineno = lineno + 1 - if line[-1:] == '\n': - line = line[:-1] - if prog.search(line): - sys.stdout.write("%s: %s: %s\n" % (fn, lineno, line)) - hits = hits + 1 - if hits: - if hits == 1: - s = "" - else: - s = "s" - print "Found", hits, "hit%s." % s - print "(Hint: right-click to open locations.)" - else: - print "No hits." + print(("Hits found: %s\n" + "(Hint: right-click to open locations.)" + % hits) if hits else "No hits.") def findfiles(self, dir, base, rec): try: @@ -131,3 +119,9 @@ class GrepDialog(SearchDialogBase): if self.top: self.top.grab_release() self.top.withdraw() + +if __name__ == "__main__": + # A human test is a bit tricky since EditorWindow() imports this module. + # Hence Idle must be restarted after editing this file for a live test. + import unittest + unittest.main('idlelib.idle_test.test_grep', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_grep.py b/Lib/idlelib/idle_test/test_grep.py new file mode 100644 index 0000000..e9f4f22 --- /dev/null +++ b/Lib/idlelib/idle_test/test_grep.py @@ -0,0 +1,82 @@ +""" !Changing this line will break Test_findfile.test_found! +Non-gui unit tests for idlelib.GrepDialog methods. +dummy_command calls grep_it calls findfiles. +An exception raised in one method will fail callers. +Otherwise, tests are mostly independent. +*** Currently only test grep_it. +""" +import unittest +from test.test_support import captured_stdout, findfile +from idlelib.idle_test.mock_tk import Var +from idlelib.GrepDialog import GrepDialog +import re + +__file__ = findfile('idlelib/idle_test') + '/test_grep.py' + +class Dummy_searchengine: + '''GrepDialog.__init__ calls parent SearchDiabolBase which attaches the + passed in SearchEngine instance as attribute 'engine'. Only a few of the + many possible self.engine.x attributes are needed here. + ''' + def getpat(self): + return self._pat + +searchengine = Dummy_searchengine() + +class Dummy_grep: + # Methods tested + #default_command = GrepDialog.default_command + grep_it = GrepDialog.grep_it.im_func + findfiles = GrepDialog.findfiles.im_func + # Other stuff needed + recvar = Var(False) + engine = searchengine + def close(self): # gui method + pass + +grep = Dummy_grep() + +class FindfilesTest(unittest.TestCase): + # findfiles is really a function, not a method, could be iterator + # test that filename return filename + # test that idlelib has many .py files + # test that recursive flag adds idle_test .py files + pass + +class Grep_itTest(unittest.TestCase): + # Test captured reports with 0 and some hits. + # Should test file names, but Windows reports have mixed / and \ separators + # from incomplete replacement, so 'later'. + + def report(self, pat): + grep.engine._pat = pat + with captured_stdout() as s: + grep.grep_it(re.compile(pat), __file__) + lines = s.getvalue().split('\n') + lines.pop() # remove bogus '' after last \n + return lines + + def test_unfound(self): + pat = 'xyz*'*7 + lines = self.report(pat) + self.assertEqual(len(lines), 2) + self.assertIn(pat, lines[0]) + self.assertEqual(lines[1], 'No hits.') + + def test_found(self): + + pat = '""" !Changing this line will break Test_findfile.test_found!' + lines = self.report(pat) + self.assertEqual(len(lines), 5) + self.assertIn(pat, lines[0]) + self.assertIn('py: 1:', lines[1]) # line number 1 + self.assertIn('2', lines[3]) # hits found 2 + self.assertTrue(lines[4].startswith('(Hint:')) + +class Default_commandTest(unittest.TestCase): + # To write this, mode OutputWindow import to top of GrepDialog + # so it can be replaced by captured_stdout in class setup/teardown. + pass + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) -- cgit v0.12