DebugClients/Python/coverage/summary.py

changeset 6219
d6c795b5ce33
parent 5178
878ce843ca9f
equal deleted inserted replaced
6218:bedab77d0fa3 6219:d6c795b5ce33
6 import sys 6 import sys
7 7
8 from coverage import env 8 from coverage import env
9 from coverage.report import Reporter 9 from coverage.report import Reporter
10 from coverage.results import Numbers 10 from coverage.results import Numbers
11 from coverage.misc import NotPython, CoverageException, output_encoding 11 from coverage.misc import NotPython, CoverageException, output_encoding, StopEverything
12 12
13 13
14 class SummaryReporter(Reporter): 14 class SummaryReporter(Reporter):
15 """A reporter for writing the summary report.""" 15 """A reporter for writing the summary report."""
16 16
23 23
24 `outfile` is a file object to write the summary to. It must be opened 24 `outfile` is a file object to write the summary to. It must be opened
25 for native strings (bytes on Python 2, Unicode on Python 3). 25 for native strings (bytes on Python 2, Unicode on Python 3).
26 26
27 """ 27 """
28 file_reporters = self.find_file_reporters(morfs) 28 if outfile is None:
29 outfile = sys.stdout
29 30
30 # Prepare the formatting strings 31 def writeout(line):
31 max_name = max([len(fr.relative_filename()) for fr in file_reporters] + [5]) 32 """Write a line to the output, adding a newline."""
33 if env.PY2:
34 line = line.encode(output_encoding())
35 outfile.write(line.rstrip())
36 outfile.write("\n")
37
38 fr_analysis = []
39 skipped_count = 0
40 total = Numbers()
41
42 fmt_err = u"%s %s: %s"
43
44 for fr in self.find_file_reporters(morfs):
45 try:
46 analysis = self.coverage._analyze(fr)
47 nums = analysis.numbers
48 total += nums
49
50 if self.config.skip_covered:
51 # Don't report on 100% files.
52 no_missing_lines = (nums.n_missing == 0)
53 no_missing_branches = (nums.n_partial_branches == 0)
54 if no_missing_lines and no_missing_branches:
55 skipped_count += 1
56 continue
57 fr_analysis.append((fr, analysis))
58 except StopEverything:
59 # Don't report this on single files, it's a systemic problem.
60 raise
61 except Exception:
62 report_it = not self.config.ignore_errors
63 if report_it:
64 typ, msg = sys.exc_info()[:2]
65 # NotPython is only raised by PythonFileReporter, which has a
66 # should_be_python() method.
67 if issubclass(typ, NotPython) and not fr.should_be_python():
68 report_it = False
69 if report_it:
70 writeout(fmt_err % (fr.relative_filename(), typ.__name__, msg))
71
72 # Prepare the formatting strings, header, and column sorting.
73 max_name = max([len(fr.relative_filename()) for (fr, analysis) in fr_analysis] + [5])
32 fmt_name = u"%%- %ds " % max_name 74 fmt_name = u"%%- %ds " % max_name
33 fmt_err = u"%s %s: %s"
34 fmt_skip_covered = u"\n%s file%s skipped due to complete coverage." 75 fmt_skip_covered = u"\n%s file%s skipped due to complete coverage."
35 76
36 header = (fmt_name % "Name") + u" Stmts Miss" 77 header = (fmt_name % "Name") + u" Stmts Miss"
37 fmt_coverage = fmt_name + u"%6d %6d" 78 fmt_coverage = fmt_name + u"%6d %6d"
38 if self.branches: 79 if self.branches:
44 if self.config.show_missing: 85 if self.config.show_missing:
45 header += u" Missing" 86 header += u" Missing"
46 fmt_coverage += u" %s" 87 fmt_coverage += u" %s"
47 rule = u"-" * len(header) 88 rule = u"-" * len(header)
48 89
49 if outfile is None: 90 column_order = dict(name=0, stmts=1, miss=2, cover=-1)
50 outfile = sys.stdout 91 if self.branches:
51 92 column_order.update(dict(branch=3, brpart=4))
52 def writeout(line):
53 """Write a line to the output, adding a newline."""
54 if env.PY2:
55 line = line.encode(output_encoding())
56 outfile.write(line.rstrip())
57 outfile.write("\n")
58 93
59 # Write the header 94 # Write the header
60 writeout(header) 95 writeout(header)
61 writeout(rule) 96 writeout(rule)
62 97
63 total = Numbers() 98 # `lines` is a list of pairs, (line text, line values). The line text
64 skipped_count = 0 99 # is a string that will be printed, and line values is a tuple of
100 # sortable values.
101 lines = []
65 102
66 for fr in file_reporters: 103 for (fr, analysis) in fr_analysis:
67 try: 104 try:
68 analysis = self.coverage._analyze(fr)
69 nums = analysis.numbers 105 nums = analysis.numbers
70 total += nums
71
72 if self.config.skip_covered:
73 # Don't report on 100% files.
74 no_missing_lines = (nums.n_missing == 0)
75 no_missing_branches = (nums.n_partial_branches == 0)
76 if no_missing_lines and no_missing_branches:
77 skipped_count += 1
78 continue
79 106
80 args = (fr.relative_filename(), nums.n_statements, nums.n_missing) 107 args = (fr.relative_filename(), nums.n_statements, nums.n_missing)
81 if self.branches: 108 if self.branches:
82 args += (nums.n_branches, nums.n_partial_branches) 109 args += (nums.n_branches, nums.n_partial_branches)
83 args += (nums.pc_covered_str,) 110 args += (nums.pc_covered_str,)
88 if branches_fmtd: 115 if branches_fmtd:
89 if missing_fmtd: 116 if missing_fmtd:
90 missing_fmtd += ", " 117 missing_fmtd += ", "
91 missing_fmtd += branches_fmtd 118 missing_fmtd += branches_fmtd
92 args += (missing_fmtd,) 119 args += (missing_fmtd,)
93 writeout(fmt_coverage % args) 120 text = fmt_coverage % args
121 # Add numeric percent coverage so that sorting makes sense.
122 args += (nums.pc_covered,)
123 lines.append((text, args))
94 except Exception: 124 except Exception:
95 report_it = not self.config.ignore_errors 125 report_it = not self.config.ignore_errors
96 if report_it: 126 if report_it:
97 typ, msg = sys.exc_info()[:2] 127 typ, msg = sys.exc_info()[:2]
98 # NotPython is only raised by PythonFileReporter, which has a 128 # NotPython is only raised by PythonFileReporter, which has a
100 if typ is NotPython and not fr.should_be_python(): 130 if typ is NotPython and not fr.should_be_python():
101 report_it = False 131 report_it = False
102 if report_it: 132 if report_it:
103 writeout(fmt_err % (fr.relative_filename(), typ.__name__, msg)) 133 writeout(fmt_err % (fr.relative_filename(), typ.__name__, msg))
104 134
135 # Sort the lines and write them out.
136 if getattr(self.config, 'sort', None):
137 position = column_order.get(self.config.sort.lower())
138 if position is None:
139 raise CoverageException("Invalid sorting option: {0!r}".format(self.config.sort))
140 lines.sort(key=lambda l: (l[1][position], l[0]))
141
142 for line in lines:
143 writeout(line[0])
144
145 # Write a TOTAl line if we had more than one file.
105 if total.n_files > 1: 146 if total.n_files > 1:
106 writeout(rule) 147 writeout(rule)
107 args = ("TOTAL", total.n_statements, total.n_missing) 148 args = ("TOTAL", total.n_statements, total.n_missing)
108 if self.branches: 149 if self.branches:
109 args += (total.n_branches, total.n_partial_branches) 150 args += (total.n_branches, total.n_partial_branches)
110 args += (total.pc_covered_str,) 151 args += (total.pc_covered_str,)
111 if self.config.show_missing: 152 if self.config.show_missing:
112 args += ("",) 153 args += ("",)
113 writeout(fmt_coverage % args) 154 writeout(fmt_coverage % args)
114 155
156 # Write other final lines.
115 if not total.n_files and not skipped_count: 157 if not total.n_files and not skipped_count:
116 raise CoverageException("No data to report.") 158 raise CoverageException("No data to report.")
117 159
118 if self.config.skip_covered and skipped_count: 160 if self.config.skip_covered and skipped_count:
119 writeout(fmt_skip_covered % (skipped_count, 's' if skipped_count > 1 else '')) 161 writeout(fmt_skip_covered % (skipped_count, 's' if skipped_count > 1 else ''))

eric ide

mercurial