coverage 7.6.7__cp311-cp311-win_amd64.whl → 7.11.1__cp311-cp311-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coverage/__init__.py +2 -0
- coverage/__main__.py +2 -0
- coverage/annotate.py +1 -2
- coverage/bytecode.py +177 -3
- coverage/cmdline.py +329 -154
- coverage/collector.py +31 -42
- coverage/config.py +166 -62
- coverage/context.py +4 -5
- coverage/control.py +164 -85
- coverage/core.py +70 -33
- coverage/data.py +3 -4
- coverage/debug.py +112 -56
- coverage/disposition.py +1 -0
- coverage/env.py +65 -55
- coverage/exceptions.py +35 -7
- coverage/execfile.py +18 -13
- coverage/files.py +23 -18
- coverage/html.py +134 -88
- coverage/htmlfiles/style.css +42 -2
- coverage/htmlfiles/style.scss +65 -1
- coverage/inorout.py +61 -44
- coverage/jsonreport.py +17 -8
- coverage/lcovreport.py +16 -20
- coverage/misc.py +50 -46
- coverage/multiproc.py +12 -7
- coverage/numbits.py +3 -4
- coverage/parser.py +193 -269
- coverage/patch.py +166 -0
- coverage/phystokens.py +24 -25
- coverage/plugin.py +13 -13
- coverage/plugin_support.py +36 -35
- coverage/python.py +9 -13
- coverage/pytracer.py +40 -33
- coverage/regions.py +2 -1
- coverage/report.py +59 -43
- coverage/report_core.py +6 -9
- coverage/results.py +118 -66
- coverage/sqldata.py +260 -210
- coverage/sqlitedb.py +33 -25
- coverage/sysmon.py +195 -157
- coverage/templite.py +6 -6
- coverage/tomlconfig.py +12 -12
- coverage/tracer.cp311-win_amd64.pyd +0 -0
- coverage/tracer.pyi +2 -0
- coverage/types.py +25 -22
- coverage/version.py +3 -18
- coverage/xmlreport.py +16 -13
- {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info}/METADATA +40 -18
- coverage-7.11.1.dist-info/RECORD +59 -0
- {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info}/WHEEL +1 -1
- coverage-7.6.7.dist-info/RECORD +0 -58
- {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info}/entry_points.txt +0 -0
- {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info/licenses}/LICENSE.txt +0 -0
- {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info}/top_level.txt +0 -0
coverage/pytracer.py
CHANGED
|
@@ -10,7 +10,6 @@ import dis
|
|
|
10
10
|
import itertools
|
|
11
11
|
import sys
|
|
12
12
|
import threading
|
|
13
|
-
|
|
14
13
|
from types import FrameType, ModuleType
|
|
15
14
|
from typing import Any, Callable, cast
|
|
16
15
|
|
|
@@ -19,15 +18,23 @@ from coverage.types import (
|
|
|
19
18
|
TArc,
|
|
20
19
|
TFileDisposition,
|
|
21
20
|
TLineNo,
|
|
21
|
+
Tracer,
|
|
22
22
|
TShouldStartContextFn,
|
|
23
23
|
TShouldTraceFn,
|
|
24
24
|
TTraceData,
|
|
25
25
|
TTraceFileData,
|
|
26
26
|
TTraceFn,
|
|
27
27
|
TWarnFn,
|
|
28
|
-
Tracer,
|
|
29
28
|
)
|
|
30
29
|
|
|
30
|
+
# I don't understand why, but if we use `cast(set[TLineNo], ...)` inside
|
|
31
|
+
# the _trace() function, we get some strange behavior on PyPy 3.10.
|
|
32
|
+
# Assigning these names here and using them below fixes the problem.
|
|
33
|
+
# See https://github.com/nedbat/coveragepy/issues/1902
|
|
34
|
+
set_TLineNo = set[TLineNo]
|
|
35
|
+
set_TArc = set[TArc]
|
|
36
|
+
|
|
37
|
+
|
|
31
38
|
# We need the YIELD_VALUE opcode below, in a comparison-friendly form.
|
|
32
39
|
# PYVERSIONS: RESUME is new in Python3.11
|
|
33
40
|
RESUME = dis.opmap.get("RESUME")
|
|
@@ -44,6 +51,7 @@ else:
|
|
|
44
51
|
|
|
45
52
|
THIS_FILE = __file__.rstrip("co")
|
|
46
53
|
|
|
54
|
+
|
|
47
55
|
class PyTracer(Tracer):
|
|
48
56
|
"""Python implementation of the raw data tracer."""
|
|
49
57
|
|
|
@@ -117,19 +125,20 @@ class PyTracer(Tracer):
|
|
|
117
125
|
|
|
118
126
|
def log(self, marker: str, *args: Any) -> None:
|
|
119
127
|
"""For hard-core logging of what this tracer is doing."""
|
|
120
|
-
with open("/tmp/debug_trace.txt", "a") as f:
|
|
128
|
+
with open("/tmp/debug_trace.txt", "a", encoding="utf-8") as f:
|
|
121
129
|
f.write(f"{marker} {self.id}[{len(self.data_stack)}]")
|
|
122
|
-
if 0:
|
|
123
|
-
f.write(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
if 0: # if you want thread ids..
|
|
131
|
+
f.write( # type: ignore[unreachable]
|
|
132
|
+
".{:x}.{:x}".format(
|
|
133
|
+
self.thread.ident,
|
|
134
|
+
self.threading.current_thread().ident,
|
|
135
|
+
)
|
|
136
|
+
)
|
|
127
137
|
f.write(" {}".format(" ".join(map(str, args))))
|
|
128
|
-
if 0:
|
|
129
|
-
f.write(" | ")
|
|
138
|
+
if 0: # if you want callers..
|
|
139
|
+
f.write(" | ") # type: ignore[unreachable]
|
|
130
140
|
stack = " / ".join(
|
|
131
|
-
(fname or "???").rpartition("/")[-1]
|
|
132
|
-
for _, fname, _, _ in self.data_stack
|
|
141
|
+
(fname or "???").rpartition("/")[-1] for _, fname, _, _ in self.data_stack
|
|
133
142
|
)
|
|
134
143
|
f.write(stack)
|
|
135
144
|
f.write("\n")
|
|
@@ -138,8 +147,8 @@ class PyTracer(Tracer):
|
|
|
138
147
|
self,
|
|
139
148
|
frame: FrameType,
|
|
140
149
|
event: str,
|
|
141
|
-
arg: Any,
|
|
142
|
-
lineno: TLineNo | None = None,
|
|
150
|
+
arg: Any, # pylint: disable=unused-argument
|
|
151
|
+
lineno: TLineNo | None = None, # pylint: disable=unused-argument
|
|
143
152
|
) -> TTraceFn | None:
|
|
144
153
|
"""The trace function passed to sys.settrace."""
|
|
145
154
|
|
|
@@ -149,11 +158,11 @@ class PyTracer(Tracer):
|
|
|
149
158
|
# f = frame; code = f.f_code
|
|
150
159
|
# self.log(":", f"{code.co_filename} {f.f_lineno} {code.co_name}()", event)
|
|
151
160
|
|
|
152
|
-
if
|
|
161
|
+
if self.stopped and sys.gettrace() == self._cached_bound_method_trace: # pylint: disable=comparison-with-callable
|
|
153
162
|
# The PyTrace.stop() method has been called, possibly by another
|
|
154
163
|
# thread, let's deactivate ourselves now.
|
|
155
164
|
if 0:
|
|
156
|
-
f = frame
|
|
165
|
+
f = frame # type: ignore[unreachable]
|
|
157
166
|
self.log("---\nX", f.f_code.co_filename, f.f_lineno)
|
|
158
167
|
while f:
|
|
159
168
|
self.log(">", f.f_code.co_filename, f.f_lineno, f.f_code.co_name, f.f_trace)
|
|
@@ -178,12 +187,12 @@ class PyTracer(Tracer):
|
|
|
178
187
|
if event == "call":
|
|
179
188
|
# Should we start a new context?
|
|
180
189
|
if self.should_start_context and self.context is None:
|
|
181
|
-
context_maybe = self.should_start_context(frame)
|
|
190
|
+
context_maybe = self.should_start_context(frame) # pylint: disable=not-callable
|
|
182
191
|
if context_maybe is not None:
|
|
183
192
|
self.context = context_maybe
|
|
184
193
|
started_context = True
|
|
185
194
|
assert self.switch_context is not None
|
|
186
|
-
self.switch_context(self.context)
|
|
195
|
+
self.switch_context(self.context) # pylint: disable=not-callable
|
|
187
196
|
else:
|
|
188
197
|
started_context = False
|
|
189
198
|
else:
|
|
@@ -239,9 +248,9 @@ class PyTracer(Tracer):
|
|
|
239
248
|
# The current opcode is guaranteed to be RESUME. The argument
|
|
240
249
|
# determines what kind of resume it is.
|
|
241
250
|
oparg = frame.f_code.co_code[frame.f_lasti + 1]
|
|
242
|
-
real_call = (oparg == 0)
|
|
251
|
+
real_call = (oparg == 0) # fmt: skip
|
|
243
252
|
else:
|
|
244
|
-
real_call = (getattr(frame, "f_lasti", -1) < 0)
|
|
253
|
+
real_call = (getattr(frame, "f_lasti", -1) < 0) # fmt: skip
|
|
245
254
|
if real_call:
|
|
246
255
|
self.last_line = -frame.f_code.co_firstlineno
|
|
247
256
|
else:
|
|
@@ -253,9 +262,9 @@ class PyTracer(Tracer):
|
|
|
253
262
|
flineno: TLineNo = frame.f_lineno
|
|
254
263
|
|
|
255
264
|
if self.trace_arcs:
|
|
256
|
-
cast(
|
|
265
|
+
cast(set_TArc, self.cur_file_data).add((self.last_line, flineno))
|
|
257
266
|
else:
|
|
258
|
-
cast(
|
|
267
|
+
cast(set_TLineNo, self.cur_file_data).add(flineno)
|
|
259
268
|
self.last_line = flineno
|
|
260
269
|
|
|
261
270
|
elif event == "return":
|
|
@@ -272,7 +281,7 @@ class PyTracer(Tracer):
|
|
|
272
281
|
# It is a real return if we aren't going to resume next.
|
|
273
282
|
if env.PYBEHAVIOR.lasti_is_yield:
|
|
274
283
|
lasti += 2
|
|
275
|
-
real_return =
|
|
284
|
+
real_return = code[lasti] != RESUME
|
|
276
285
|
else:
|
|
277
286
|
if code[lasti] == RETURN_VALUE:
|
|
278
287
|
real_return = True
|
|
@@ -286,7 +295,7 @@ class PyTracer(Tracer):
|
|
|
286
295
|
real_return = True
|
|
287
296
|
if real_return:
|
|
288
297
|
first = frame.f_code.co_firstlineno
|
|
289
|
-
cast(
|
|
298
|
+
cast(set_TArc, self.cur_file_data).add((self.last_line, -first))
|
|
290
299
|
|
|
291
300
|
# Leaving this function, pop the filename stack.
|
|
292
301
|
self.cur_file_data, self.cur_file_name, self.last_line, self.started_context = (
|
|
@@ -296,7 +305,8 @@ class PyTracer(Tracer):
|
|
|
296
305
|
if self.started_context:
|
|
297
306
|
assert self.switch_context is not None
|
|
298
307
|
self.context = None
|
|
299
|
-
self.switch_context(None)
|
|
308
|
+
self.switch_context(None) # pylint: disable=not-callable
|
|
309
|
+
|
|
300
310
|
return self._cached_bound_method_trace
|
|
301
311
|
|
|
302
312
|
def start(self) -> TTraceFn:
|
|
@@ -330,22 +340,19 @@ class PyTracer(Tracer):
|
|
|
330
340
|
# Called on a different thread than started us: we can't unhook
|
|
331
341
|
# ourselves, but we've set the flag that we should stop, so we
|
|
332
342
|
# won't do any more tracing.
|
|
333
|
-
#self.log("~", "stopping on different threads")
|
|
343
|
+
# self.log("~", "stopping on different threads")
|
|
334
344
|
return
|
|
335
345
|
|
|
336
346
|
# PyPy clears the trace function before running atexit functions,
|
|
337
347
|
# so don't warn if we are in atexit on PyPy and the trace function
|
|
338
348
|
# has changed to None. Metacoverage also messes this up, so don't
|
|
339
349
|
# warn if we are measuring ourselves.
|
|
340
|
-
suppress_warning = (
|
|
341
|
-
(env.PYPY and self.in_atexit and tf is None)
|
|
342
|
-
or env.METACOV
|
|
343
|
-
)
|
|
350
|
+
suppress_warning = (env.PYPY and self.in_atexit and tf is None) or env.METACOV
|
|
344
351
|
if self.warn and not suppress_warning:
|
|
345
|
-
if tf != self._cached_bound_method_trace:
|
|
352
|
+
if tf != self._cached_bound_method_trace: # pylint: disable=comparison-with-callable
|
|
346
353
|
self.warn(
|
|
347
|
-
"Trace function changed, data is likely wrong: "
|
|
348
|
-
f"{tf!r} != {self._cached_bound_method_trace!r}",
|
|
354
|
+
"Trace function changed, data is likely wrong: "
|
|
355
|
+
+ f"{tf!r} != {self._cached_bound_method_trace!r}",
|
|
349
356
|
slug="trace-changed",
|
|
350
357
|
)
|
|
351
358
|
|
coverage/regions.py
CHANGED
|
@@ -7,7 +7,6 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import ast
|
|
9
9
|
import dataclasses
|
|
10
|
-
|
|
11
10
|
from typing import cast
|
|
12
11
|
|
|
13
12
|
from coverage.plugin import CodeRegion
|
|
@@ -16,6 +15,7 @@ from coverage.plugin import CodeRegion
|
|
|
16
15
|
@dataclasses.dataclass
|
|
17
16
|
class Context:
|
|
18
17
|
"""The nested named context of a function or class."""
|
|
18
|
+
|
|
19
19
|
name: str
|
|
20
20
|
kind: str
|
|
21
21
|
lines: set[int]
|
|
@@ -28,6 +28,7 @@ class RegionFinder:
|
|
|
28
28
|
attribute.
|
|
29
29
|
|
|
30
30
|
"""
|
|
31
|
+
|
|
31
32
|
def __init__(self) -> None:
|
|
32
33
|
self.regions: list[CodeRegion] = []
|
|
33
34
|
self.context: list[Context] = []
|
coverage/report.py
CHANGED
|
@@ -6,12 +6,11 @@
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import sys
|
|
9
|
-
|
|
10
|
-
from typing import Any, IO, TYPE_CHECKING
|
|
11
9
|
from collections.abc import Iterable
|
|
10
|
+
from typing import IO, TYPE_CHECKING, Any
|
|
12
11
|
|
|
13
12
|
from coverage.exceptions import ConfigError, NoDataError
|
|
14
|
-
from coverage.misc import human_sorted_items
|
|
13
|
+
from coverage.misc import human_sorted_items, plural
|
|
15
14
|
from coverage.plugin import FileReporter
|
|
16
15
|
from coverage.report_core import get_analysis_to_report
|
|
17
16
|
from coverage.results import Analysis, Numbers
|
|
@@ -32,7 +31,7 @@ class SummaryReporter:
|
|
|
32
31
|
self.output_format = self.config.format or "text"
|
|
33
32
|
if self.output_format not in {"text", "markdown", "total"}:
|
|
34
33
|
raise ConfigError(f"Unknown report format choice: {self.output_format!r}")
|
|
35
|
-
self.
|
|
34
|
+
self.fr_analyses: list[tuple[FileReporter, Analysis]] = []
|
|
36
35
|
self.skipped_count = 0
|
|
37
36
|
self.empty_count = 0
|
|
38
37
|
self.total = Numbers(precision=self.config.precision)
|
|
@@ -47,7 +46,7 @@ class SummaryReporter:
|
|
|
47
46
|
"""Write a list of strings, joined together."""
|
|
48
47
|
self.write("".join(items))
|
|
49
48
|
|
|
50
|
-
def
|
|
49
|
+
def report_text(
|
|
51
50
|
self,
|
|
52
51
|
header: list[str],
|
|
53
52
|
lines_values: list[list[Any]],
|
|
@@ -75,10 +74,7 @@ class SummaryReporter:
|
|
|
75
74
|
Cover="{:>{n}}",
|
|
76
75
|
Missing="{:>10}",
|
|
77
76
|
)
|
|
78
|
-
header_items = [
|
|
79
|
-
formats[item].format(item, name_len=max_name, n=max_n)
|
|
80
|
-
for item in header
|
|
81
|
-
]
|
|
77
|
+
header_items = [formats[item].format(item, name_len=max_name, n=max_n) for item in header]
|
|
82
78
|
header_str = "".join(header_items)
|
|
83
79
|
rule = "-" * len(header_str)
|
|
84
80
|
|
|
@@ -86,29 +82,36 @@ class SummaryReporter:
|
|
|
86
82
|
self.write(header_str)
|
|
87
83
|
self.write(rule)
|
|
88
84
|
|
|
89
|
-
|
|
85
|
+
# Write the data lines
|
|
86
|
+
formats.update(
|
|
87
|
+
dict(
|
|
88
|
+
Cover="{:>{n}}%",
|
|
89
|
+
Missing=" {:9}",
|
|
90
|
+
)
|
|
91
|
+
)
|
|
90
92
|
for values in lines_values:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
self.write_items(
|
|
94
|
+
(
|
|
95
|
+
formats[item].format(str(value), name_len=max_name, n=max_n - 1)
|
|
96
|
+
for item, value in zip(header, values)
|
|
97
|
+
)
|
|
98
|
+
)
|
|
97
99
|
|
|
98
100
|
# Write a TOTAL line
|
|
99
101
|
if lines_values:
|
|
100
102
|
self.write(rule)
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
self.write_items(
|
|
105
|
+
(
|
|
106
|
+
formats[item].format(str(value), name_len=max_name, n=max_n - 1)
|
|
107
|
+
for item, value in zip(header, total_line)
|
|
108
|
+
)
|
|
109
|
+
)
|
|
107
110
|
|
|
108
111
|
for end_line in end_lines:
|
|
109
112
|
self.write(end_line)
|
|
110
113
|
|
|
111
|
-
def
|
|
114
|
+
def report_markdown(
|
|
112
115
|
self,
|
|
113
116
|
header: list[str],
|
|
114
117
|
lines_values: list[list[Any]],
|
|
@@ -138,25 +141,38 @@ class SummaryReporter:
|
|
|
138
141
|
max_n = max(len(total_line[header.index("Cover")]) + 6, len(" Cover "))
|
|
139
142
|
header_items = [formats[item].format(item, name_len=max_name, n=max_n) for item in header]
|
|
140
143
|
header_str = "".join(header_items)
|
|
141
|
-
rule_str = "|" + " ".join(
|
|
142
|
-
["
|
|
144
|
+
rule_str = "|" + " ".join(
|
|
145
|
+
["- |".rjust(len(header_items[0]) - 1, "-")]
|
|
146
|
+
+ ["-: |".rjust(len(item) - 1, "-") for item in header_items[1:]],
|
|
143
147
|
)
|
|
144
148
|
|
|
145
149
|
# Write the header
|
|
146
150
|
self.write(header_str)
|
|
147
151
|
self.write(rule_str)
|
|
148
152
|
|
|
153
|
+
# Write the data lines
|
|
149
154
|
for values in lines_values:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
formats.update(
|
|
156
|
+
dict(
|
|
157
|
+
Cover="{:>{n}}% |",
|
|
158
|
+
)
|
|
159
|
+
)
|
|
160
|
+
self.write_items(
|
|
161
|
+
(
|
|
162
|
+
formats[item].format(
|
|
163
|
+
str(value).replace("_", "\\_"), name_len=max_name, n=max_n - 1
|
|
164
|
+
)
|
|
165
|
+
for item, value in zip(header, values)
|
|
166
|
+
)
|
|
167
|
+
)
|
|
157
168
|
|
|
158
169
|
# Write the TOTAL line
|
|
159
|
-
formats.update(
|
|
170
|
+
formats.update(
|
|
171
|
+
dict(
|
|
172
|
+
Name="|{:>{name_len}} |",
|
|
173
|
+
Cover="{:>{n}} |",
|
|
174
|
+
),
|
|
175
|
+
)
|
|
160
176
|
total_line_items: list[str] = []
|
|
161
177
|
for item, value in zip(header, total_line):
|
|
162
178
|
if value == "":
|
|
@@ -167,6 +183,7 @@ class SummaryReporter:
|
|
|
167
183
|
insert = f" **{value}**"
|
|
168
184
|
total_line_items += formats[item].format(insert, name_len=max_name, n=max_n)
|
|
169
185
|
self.write_items(total_line_items)
|
|
186
|
+
|
|
170
187
|
for end_line in end_lines:
|
|
171
188
|
self.write(end_line)
|
|
172
189
|
|
|
@@ -209,9 +226,8 @@ class SummaryReporter:
|
|
|
209
226
|
# `lines_values` is list of lists of sortable values.
|
|
210
227
|
lines_values = []
|
|
211
228
|
|
|
212
|
-
for
|
|
229
|
+
for fr, analysis in self.fr_analyses:
|
|
213
230
|
nums = analysis.numbers
|
|
214
|
-
|
|
215
231
|
args = [fr.relative_filename(), nums.n_statements, nums.n_missing]
|
|
216
232
|
if self.branches:
|
|
217
233
|
args += [nums.n_branches, nums.n_partial_branches]
|
|
@@ -251,18 +267,18 @@ class SummaryReporter:
|
|
|
251
267
|
# Create other final lines.
|
|
252
268
|
end_lines = []
|
|
253
269
|
if self.config.skip_covered and self.skipped_count:
|
|
254
|
-
|
|
270
|
+
files = plural(self.skipped_count, "file")
|
|
255
271
|
end_lines.append(
|
|
256
|
-
f"\n{self.skipped_count}
|
|
272
|
+
f"\n{self.skipped_count} {files} skipped due to complete coverage.",
|
|
257
273
|
)
|
|
258
274
|
if self.config.skip_empty and self.empty_count:
|
|
259
|
-
|
|
260
|
-
end_lines.append(f"\n{self.empty_count} empty
|
|
275
|
+
files = plural(self.empty_count, "file")
|
|
276
|
+
end_lines.append(f"\n{self.empty_count} empty {files} skipped.")
|
|
261
277
|
|
|
262
278
|
if self.output_format == "markdown":
|
|
263
|
-
formatter = self.
|
|
279
|
+
formatter = self.report_markdown
|
|
264
280
|
else:
|
|
265
|
-
formatter = self.
|
|
281
|
+
formatter = self.report_text
|
|
266
282
|
formatter(header, lines_values, total_line, end_lines)
|
|
267
283
|
|
|
268
284
|
def report_one_file(self, fr: FileReporter, analysis: Analysis) -> None:
|
|
@@ -270,8 +286,8 @@ class SummaryReporter:
|
|
|
270
286
|
nums = analysis.numbers
|
|
271
287
|
self.total += nums
|
|
272
288
|
|
|
273
|
-
no_missing_lines = (nums.n_missing == 0)
|
|
274
|
-
no_missing_branches = (nums.n_partial_branches == 0)
|
|
289
|
+
no_missing_lines = (nums.n_missing == 0) # fmt: skip
|
|
290
|
+
no_missing_branches = (nums.n_partial_branches == 0) # fmt: skip
|
|
275
291
|
if self.config.skip_covered and no_missing_lines and no_missing_branches:
|
|
276
292
|
# Don't report on 100% files.
|
|
277
293
|
self.skipped_count += 1
|
|
@@ -279,4 +295,4 @@ class SummaryReporter:
|
|
|
279
295
|
# Don't report on empty files.
|
|
280
296
|
self.empty_count += 1
|
|
281
297
|
else:
|
|
282
|
-
self.
|
|
298
|
+
self.fr_analyses.append((fr, analysis))
|
coverage/report_core.py
CHANGED
|
@@ -6,14 +6,11 @@
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import sys
|
|
9
|
-
|
|
10
|
-
from typing import
|
|
11
|
-
Callable, IO, Protocol, TYPE_CHECKING,
|
|
12
|
-
)
|
|
13
|
-
from collections.abc import Iterable, Iterator
|
|
9
|
+
from collections.abc import Iterable
|
|
10
|
+
from typing import IO, TYPE_CHECKING, Callable, Protocol
|
|
14
11
|
|
|
15
12
|
from coverage.exceptions import NoDataError, NotPython
|
|
16
|
-
from coverage.files import
|
|
13
|
+
from coverage.files import GlobMatcher, prep_patterns
|
|
17
14
|
from coverage.misc import ensure_dir_for_file, file_be_gone
|
|
18
15
|
from coverage.plugin import FileReporter
|
|
19
16
|
from coverage.results import Analysis
|
|
@@ -68,13 +65,13 @@ def render_report(
|
|
|
68
65
|
if file_to_close is not None:
|
|
69
66
|
file_to_close.close()
|
|
70
67
|
if delete_file:
|
|
71
|
-
file_be_gone(output_path)
|
|
68
|
+
file_be_gone(output_path) # pragma: part covered (doesn't return)
|
|
72
69
|
|
|
73
70
|
|
|
74
71
|
def get_analysis_to_report(
|
|
75
72
|
coverage: Coverage,
|
|
76
73
|
morfs: Iterable[TMorf] | None,
|
|
77
|
-
) ->
|
|
74
|
+
) -> Iterable[tuple[FileReporter, Analysis]]:
|
|
78
75
|
"""Get the files to report on.
|
|
79
76
|
|
|
80
77
|
For each morf in `morfs`, if it should be reported on (based on the omit
|
|
@@ -104,7 +101,7 @@ def get_analysis_to_report(
|
|
|
104
101
|
# explicitly suppress those errors.
|
|
105
102
|
# NotPython is only raised by PythonFileReporter, which has a
|
|
106
103
|
# should_be_python() method.
|
|
107
|
-
if fr.should_be_python():
|
|
104
|
+
if fr.should_be_python(): # type: ignore[attr-defined]
|
|
108
105
|
if config.ignore_errors:
|
|
109
106
|
msg = f"Couldn't parse Python file '{fr.filename}'"
|
|
110
107
|
coverage._warn(msg, slug="couldnt-parse")
|