diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -382,10 +382,29 @@ class TestCommandLine(unittest.TestCase) def test_listfuncs_flag_success(self): with open(TESTFN, 'w') as fd: self.addCleanup(unlink, TESTFN) fd.write("a = 1\n") status, stdout, stderr = assert_python_ok('-m', 'trace', '-l', TESTFN) self.assertIn(b'functions called:', stdout) + def test_count_and_summary(self): + name = TESTFN + '.py' + with open(name, 'w') as fd: + self.addCleanup(unlink, name) + fd.write("""\ +x = 1 +y = 2 + +def f(): + return x + y + +for i in range(10): + f() + """) + status, stdout, stderr = assert_python_ok('-m', 'trace', '-cs', name) + self.assertEqual(status, 0) + self.assertIn(b'lines cov% module (path)', stdout) + self.assertIn(('6 100%% %s (%s)' % (TESTFN, name)).encode(), stdout) + if __name__ == '__main__': unittest.main() diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -279,32 +279,28 @@ class CoverageResults: modulename = _fullmodname(filename) # If desired, get a list of the line numbers which represent # executable content (returned as a dict for better lookup speed) if show_missing: lnotab = _find_executable_linenos(filename) else: lnotab = {} - if lnotab: - source = linecache.getlines(filename) - coverpath = os.path.join(dir, modulename + ".cover") - with open(filename, 'rb') as fp: - encoding, _ = tokenize.detect_encoding(fp.readline) - n_hits, n_lines = self.write_results_file(coverpath, source, - lnotab, count, encoding) - if summary and n_lines: - percent = int(100 * n_hits / n_lines) - sums[modulename] = n_lines, percent, modulename, filename - + source = linecache.getlines(filename) + coverpath = os.path.join(dir, modulename + ".cover") + encoding = _detect_file_encoding(filename) + n_hits, n_lines = self.write_results_file(coverpath, source, + lnotab, count, encoding) + if summary and n_lines: + percent = int(100 * n_hits / n_lines) + sums[modulename] = n_lines, percent, modulename, filename if summary and sums: print("lines cov% module (path)") for m in sorted(sums): - n_lines, percent, modulename, filename = sums[m] print("%5d %3d%% %s (%s)" % sums[m]) if self.outfile: # try and store counts and module info into self.outfile try: pickle.dump((self.counts, self.calledfuncs, self.callers), open(self.outfile, 'wb'), 1) except OSError as err: @@ -340,16 +336,26 @@ class CoverageResults: outfile.write(">>>>>> ") n_lines += 1 else: outfile.write(" ") outfile.write(line.expandtabs(8)) return n_hits, n_lines +def _detect_file_encoding(filename): + try: + with open(filename, 'rb') as fp: + encoding, _ = tokenize.detect_encoding(fp.readline) + return encoding + except OSError as err: + print(("trace: Could not detect encoding of %r: %s" + "- skipping" % (filename, err)), file=sys.stderr) + return None + def _find_lines_from_code(code, strs): """Return dict where keys are lines in the line number table.""" linenos = {} for _, lineno in dis.findlinestarts(code): if lineno not in strs: linenos[lineno] = 1