|
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
|
2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt |
|
3 |
1 """Summary reporting""" |
4 """Summary reporting""" |
2 |
5 |
3 import sys |
6 import sys |
4 |
7 |
5 from .report import Reporter |
8 from coverage.report import Reporter |
6 from .results import Numbers |
9 from coverage.results import Numbers |
7 from .misc import NotPython |
10 from coverage.misc import NotPython, CoverageException |
8 |
11 |
9 |
12 |
10 class SummaryReporter(Reporter): |
13 class SummaryReporter(Reporter): |
11 """A reporter for writing the summary report.""" |
14 """A reporter for writing the summary report.""" |
12 |
15 |
18 """Writes a report summarizing coverage statistics per module. |
21 """Writes a report summarizing coverage statistics per module. |
19 |
22 |
20 `outfile` is a file object to write the summary to. |
23 `outfile` is a file object to write the summary to. |
21 |
24 |
22 """ |
25 """ |
23 self.find_code_units(morfs) |
26 self.find_file_reporters(morfs) |
24 |
27 |
25 # Prepare the formatting strings |
28 # Prepare the formatting strings |
26 max_name = max([len(cu.name) for cu in self.code_units] + [5]) |
29 max_name = max([len(fr.relative_filename()) for fr in self.file_reporters] + [5]) |
27 fmt_name = "%%- %ds " % max_name |
30 fmt_name = "%%- %ds " % max_name |
28 fmt_err = "%s %s: %s\n" |
31 fmt_err = "%s %s: %s\n" |
|
32 fmt_skip_covered = "\n%s file%s skipped due to complete coverage.\n" |
|
33 |
29 header = (fmt_name % "Name") + " Stmts Miss" |
34 header = (fmt_name % "Name") + " Stmts Miss" |
30 fmt_coverage = fmt_name + "%6d %6d" |
35 fmt_coverage = fmt_name + "%6d %6d" |
31 if self.branches: |
36 if self.branches: |
32 header += " Branch BrMiss" |
37 header += " Branch BrPart" |
33 fmt_coverage += " %6d %6d" |
38 fmt_coverage += " %6d %6d" |
34 width100 = Numbers.pc_str_width() |
39 width100 = Numbers.pc_str_width() |
35 header += "%*s" % (width100+4, "Cover") |
40 header += "%*s" % (width100+4, "Cover") |
36 fmt_coverage += "%%%ds%%%%" % (width100+3,) |
41 fmt_coverage += "%%%ds%%%%" % (width100+3,) |
37 if self.config.show_missing: |
42 if self.config.show_missing: |
47 # Write the header |
52 # Write the header |
48 outfile.write(header) |
53 outfile.write(header) |
49 outfile.write(rule) |
54 outfile.write(rule) |
50 |
55 |
51 total = Numbers() |
56 total = Numbers() |
|
57 skipped_count = 0 |
52 |
58 |
53 for cu in self.code_units: |
59 for fr in self.file_reporters: |
54 try: |
60 try: |
55 analysis = self.coverage._analyze(cu) |
61 analysis = self.coverage._analyze(fr) |
56 nums = analysis.numbers |
62 nums = analysis.numbers |
57 args = (cu.name, nums.n_statements, nums.n_missing) |
63 |
|
64 if self.config.skip_covered: |
|
65 # Don't report on 100% files. |
|
66 no_missing_lines = (nums.n_missing == 0) |
|
67 no_missing_branches = (nums.n_partial_branches == 0) |
|
68 if no_missing_lines and no_missing_branches: |
|
69 skipped_count += 1 |
|
70 continue |
|
71 |
|
72 args = (fr.relative_filename(), nums.n_statements, nums.n_missing) |
58 if self.branches: |
73 if self.branches: |
59 args += (nums.n_branches, nums.n_missing_branches) |
74 args += (nums.n_branches, nums.n_partial_branches) |
60 args += (nums.pc_covered_str,) |
75 args += (nums.pc_covered_str,) |
61 if self.config.show_missing: |
76 if self.config.show_missing: |
62 args += (analysis.missing_formatted(),) |
77 missing_fmtd = analysis.missing_formatted() |
|
78 if self.branches: |
|
79 branches_fmtd = analysis.arcs_missing_formatted() |
|
80 if branches_fmtd: |
|
81 if missing_fmtd: |
|
82 missing_fmtd += ", " |
|
83 missing_fmtd += branches_fmtd |
|
84 args += (missing_fmtd,) |
63 outfile.write(fmt_coverage % args) |
85 outfile.write(fmt_coverage % args) |
64 total += nums |
86 total += nums |
65 except KeyboardInterrupt: # pragma: not covered |
87 except Exception: |
66 raise |
|
67 except: |
|
68 report_it = not self.config.ignore_errors |
88 report_it = not self.config.ignore_errors |
69 if report_it: |
89 if report_it: |
70 typ, msg = sys.exc_info()[:2] |
90 typ, msg = sys.exc_info()[:2] |
71 if typ is NotPython and not cu.should_be_python(): |
91 # NotPython is only raised by PythonFileReporter, which has a |
|
92 # should_be_python() method. |
|
93 if typ is NotPython and not fr.should_be_python(): |
72 report_it = False |
94 report_it = False |
73 if report_it: |
95 if report_it: |
74 outfile.write(fmt_err % (cu.name, typ.__name__, msg)) |
96 outfile.write(fmt_err % (fr.relative_filename(), typ.__name__, msg)) |
75 |
97 |
76 if total.n_files > 1: |
98 if total.n_files > 1: |
77 outfile.write(rule) |
99 outfile.write(rule) |
78 args = ("TOTAL", total.n_statements, total.n_missing) |
100 args = ("TOTAL", total.n_statements, total.n_missing) |
79 if self.branches: |
101 if self.branches: |
80 args += (total.n_branches, total.n_missing_branches) |
102 args += (total.n_branches, total.n_partial_branches) |
81 args += (total.pc_covered_str,) |
103 args += (total.pc_covered_str,) |
82 if self.config.show_missing: |
104 if self.config.show_missing: |
83 args += ("",) |
105 args += ("",) |
84 outfile.write(fmt_coverage % args) |
106 outfile.write(fmt_coverage % args) |
85 |
107 |
86 return total.pc_covered |
108 if not total.n_files and not skipped_count: |
|
109 raise CoverageException("No data to report.") |
|
110 |
|
111 if self.config.skip_covered and skipped_count: |
|
112 outfile.write(fmt_skip_covered % (skipped_count, 's' if skipped_count > 1 else '')) |
|
113 |
|
114 return total.n_statements and total.pc_covered |
87 |
115 |
88 # |
116 # |
89 # eflag: FileType = Python2 |
117 # eflag: FileType = Python2 |