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