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/results.py
CHANGED
|
@@ -7,8 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import collections
|
|
9
9
|
import dataclasses
|
|
10
|
-
|
|
11
|
-
from collections.abc import Container, Iterable
|
|
10
|
+
from collections.abc import Iterable
|
|
12
11
|
from typing import TYPE_CHECKING
|
|
13
12
|
|
|
14
13
|
from coverage.exceptions import ConfigError
|
|
@@ -34,16 +33,15 @@ def analysis_from_file_reporter(
|
|
|
34
33
|
|
|
35
34
|
if has_arcs:
|
|
36
35
|
arc_possibilities_set = file_reporter.arcs()
|
|
37
|
-
arcs = data.arcs(filename) or []
|
|
36
|
+
arcs: Iterable[TArc] = data.arcs(filename) or []
|
|
37
|
+
arcs = file_reporter.translate_arcs(arcs)
|
|
38
38
|
|
|
39
39
|
# Reduce the set of arcs to the ones that could be branches.
|
|
40
40
|
dests = collections.defaultdict(set)
|
|
41
41
|
for fromno, tono in arc_possibilities_set:
|
|
42
42
|
dests[fromno].add(tono)
|
|
43
43
|
single_dests = {
|
|
44
|
-
fromno: list(tonos)[0]
|
|
45
|
-
for fromno, tonos in dests.items()
|
|
46
|
-
if len(tonos) == 1
|
|
44
|
+
fromno: list(tonos)[0] for fromno, tonos in dests.items() if len(tonos) == 1
|
|
47
45
|
}
|
|
48
46
|
new_arcs = set()
|
|
49
47
|
for fromno, tono in arcs:
|
|
@@ -99,8 +97,8 @@ class Analysis:
|
|
|
99
97
|
if self.has_arcs:
|
|
100
98
|
n_branches = self._total_branches()
|
|
101
99
|
mba = self.missing_branch_arcs()
|
|
102
|
-
n_partial_branches = sum(len(v) for k,v in mba.items() if k not in self.missing)
|
|
103
|
-
n_missing_branches = sum(len(v) for k,v in mba.items())
|
|
100
|
+
n_partial_branches = sum(len(v) for k, v in mba.items() if k not in self.missing)
|
|
101
|
+
n_missing_branches = sum(len(v) for k, v in mba.items())
|
|
104
102
|
else:
|
|
105
103
|
n_branches = n_partial_branches = n_missing_branches = 0
|
|
106
104
|
|
|
@@ -115,50 +113,6 @@ class Analysis:
|
|
|
115
113
|
n_missing_branches=n_missing_branches,
|
|
116
114
|
)
|
|
117
115
|
|
|
118
|
-
def narrow(self, lines: Container[TLineNo]) -> Analysis:
|
|
119
|
-
"""Create a narrowed Analysis.
|
|
120
|
-
|
|
121
|
-
The current analysis is copied to make a new one that only considers
|
|
122
|
-
the lines in `lines`.
|
|
123
|
-
"""
|
|
124
|
-
|
|
125
|
-
statements = {lno for lno in self.statements if lno in lines}
|
|
126
|
-
excluded = {lno for lno in self.excluded if lno in lines}
|
|
127
|
-
executed = {lno for lno in self.executed if lno in lines}
|
|
128
|
-
|
|
129
|
-
if self.has_arcs:
|
|
130
|
-
arc_possibilities_set = {
|
|
131
|
-
(a, b) for a, b in self.arc_possibilities_set
|
|
132
|
-
if a in lines or b in lines
|
|
133
|
-
}
|
|
134
|
-
arcs_executed_set = {
|
|
135
|
-
(a, b) for a, b in self.arcs_executed_set
|
|
136
|
-
if a in lines or b in lines
|
|
137
|
-
}
|
|
138
|
-
exit_counts = {
|
|
139
|
-
lno: num for lno, num in self.exit_counts.items()
|
|
140
|
-
if lno in lines
|
|
141
|
-
}
|
|
142
|
-
no_branch = {lno for lno in self.no_branch if lno in lines}
|
|
143
|
-
else:
|
|
144
|
-
arc_possibilities_set = set()
|
|
145
|
-
arcs_executed_set = set()
|
|
146
|
-
exit_counts = {}
|
|
147
|
-
no_branch = set()
|
|
148
|
-
|
|
149
|
-
return Analysis(
|
|
150
|
-
precision=self.precision,
|
|
151
|
-
filename=self.filename,
|
|
152
|
-
has_arcs=self.has_arcs,
|
|
153
|
-
statements=statements,
|
|
154
|
-
excluded=excluded,
|
|
155
|
-
executed=executed,
|
|
156
|
-
arc_possibilities_set=arc_possibilities_set,
|
|
157
|
-
arcs_executed_set=arcs_executed_set,
|
|
158
|
-
exit_counts=exit_counts,
|
|
159
|
-
no_branch=no_branch,
|
|
160
|
-
)
|
|
161
|
-
|
|
162
116
|
def missing_formatted(self, branches: bool = False) -> str:
|
|
163
117
|
"""The missing line numbers, formatted nicely.
|
|
164
118
|
|
|
@@ -177,16 +131,17 @@ class Analysis:
|
|
|
177
131
|
def arcs_missing(self) -> list[TArc]:
|
|
178
132
|
"""Returns a sorted list of the un-executed arcs in the code."""
|
|
179
133
|
missing = (
|
|
180
|
-
p
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
134
|
+
p
|
|
135
|
+
for p in self.arc_possibilities
|
|
136
|
+
if p not in self.arcs_executed_set
|
|
137
|
+
and p[0] not in self.no_branch
|
|
138
|
+
and p[1] not in self.excluded
|
|
184
139
|
)
|
|
185
140
|
return sorted(missing)
|
|
186
141
|
|
|
187
142
|
def _branch_lines(self) -> list[TLineNo]:
|
|
188
143
|
"""Returns a list of line numbers that have more than one exit."""
|
|
189
|
-
return [l1 for l1,count in self.exit_counts.items() if count > 1]
|
|
144
|
+
return [l1 for l1, count in self.exit_counts.items() if count > 1]
|
|
190
145
|
|
|
191
146
|
def _total_branches(self) -> int:
|
|
192
147
|
"""How many total branches are there?"""
|
|
@@ -202,8 +157,7 @@ class Analysis:
|
|
|
202
157
|
branch_lines = set(self._branch_lines())
|
|
203
158
|
mba = collections.defaultdict(list)
|
|
204
159
|
for l1, l2 in missing:
|
|
205
|
-
|
|
206
|
-
continue
|
|
160
|
+
assert l1 != l2, f"In {self.filename}, didn't expect {l1} == {l2}"
|
|
207
161
|
if l1 in branch_lines:
|
|
208
162
|
mba[l1].append(l2)
|
|
209
163
|
return mba
|
|
@@ -219,8 +173,7 @@ class Analysis:
|
|
|
219
173
|
branch_lines = set(self._branch_lines())
|
|
220
174
|
eba = collections.defaultdict(list)
|
|
221
175
|
for l1, l2 in self.arcs_executed:
|
|
222
|
-
|
|
223
|
-
continue
|
|
176
|
+
assert l1 != l2, f"Oops: Didn't think this could happen: {l1 = }, {l2 = }"
|
|
224
177
|
if (l1, l2) not in self.arc_possibilities_set:
|
|
225
178
|
continue
|
|
226
179
|
if l1 in branch_lines:
|
|
@@ -232,6 +185,7 @@ class Analysis:
|
|
|
232
185
|
|
|
233
186
|
Returns a dict mapping line numbers to a tuple:
|
|
234
187
|
(total_exits, taken_exits).
|
|
188
|
+
|
|
235
189
|
"""
|
|
236
190
|
|
|
237
191
|
missing_arcs = self.missing_branch_arcs()
|
|
@@ -243,6 +197,104 @@ class Analysis:
|
|
|
243
197
|
return stats
|
|
244
198
|
|
|
245
199
|
|
|
200
|
+
TRegionLines = frozenset[TLineNo]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class AnalysisNarrower:
|
|
204
|
+
"""
|
|
205
|
+
For reducing an `Analysis` to a subset of its lines.
|
|
206
|
+
|
|
207
|
+
Originally this was a simpler method on Analysis, but that led to quadratic
|
|
208
|
+
behavior. This class does the bulk of the work up-front to provide the
|
|
209
|
+
same results in linear time.
|
|
210
|
+
|
|
211
|
+
Create an AnalysisNarrower from an Analysis, bulk-add region lines to it
|
|
212
|
+
with `add_regions`, then individually request new narrowed Analysis objects
|
|
213
|
+
for each region with `narrow`. Doing most of the work in limited calls to
|
|
214
|
+
`add_regions` lets us avoid poor performance.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
# In this class, regions are represented by a frozenset of their lines.
|
|
218
|
+
|
|
219
|
+
def __init__(self, analysis: Analysis) -> None:
|
|
220
|
+
self.analysis = analysis
|
|
221
|
+
self.region2arc_possibilities: dict[TRegionLines, set[TArc]] = collections.defaultdict(set)
|
|
222
|
+
self.region2arc_executed: dict[TRegionLines, set[TArc]] = collections.defaultdict(set)
|
|
223
|
+
self.region2exit_counts: dict[TRegionLines, dict[TLineNo, int]] = collections.defaultdict(
|
|
224
|
+
dict
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
def add_regions(self, liness: Iterable[set[TLineNo]]) -> None:
|
|
228
|
+
"""
|
|
229
|
+
Pre-process a number of sets of line numbers. Later calls to `narrow`
|
|
230
|
+
with one of these sets will provide a narrowed Analysis.
|
|
231
|
+
"""
|
|
232
|
+
if self.analysis.has_arcs:
|
|
233
|
+
line2region: dict[TLineNo, TRegionLines] = {}
|
|
234
|
+
|
|
235
|
+
for lines in liness:
|
|
236
|
+
fzlines = frozenset(lines)
|
|
237
|
+
for line in lines:
|
|
238
|
+
line2region[line] = fzlines
|
|
239
|
+
|
|
240
|
+
def collect_arcs(
|
|
241
|
+
arc_set: set[TArc],
|
|
242
|
+
region2arcs: dict[TRegionLines, set[TArc]],
|
|
243
|
+
) -> None:
|
|
244
|
+
for a, b in arc_set:
|
|
245
|
+
if r := line2region.get(a):
|
|
246
|
+
region2arcs[r].add((a, b))
|
|
247
|
+
if r := line2region.get(b):
|
|
248
|
+
region2arcs[r].add((a, b))
|
|
249
|
+
|
|
250
|
+
collect_arcs(self.analysis.arc_possibilities_set, self.region2arc_possibilities)
|
|
251
|
+
collect_arcs(self.analysis.arcs_executed_set, self.region2arc_executed)
|
|
252
|
+
|
|
253
|
+
for lno, num in self.analysis.exit_counts.items():
|
|
254
|
+
if r := line2region.get(lno):
|
|
255
|
+
self.region2exit_counts[r][lno] = num
|
|
256
|
+
|
|
257
|
+
def narrow(self, lines: set[TLineNo]) -> Analysis:
|
|
258
|
+
"""Create a narrowed Analysis.
|
|
259
|
+
|
|
260
|
+
The current analysis is copied to make a new one that only considers
|
|
261
|
+
the lines in `lines`.
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
# Technically, the set intersections in this method are still O(N**2)
|
|
265
|
+
# since this method is called N times, but they're very fast and moving
|
|
266
|
+
# them to `add_regions` won't avoid the quadratic time.
|
|
267
|
+
|
|
268
|
+
statements = self.analysis.statements & lines
|
|
269
|
+
excluded = self.analysis.excluded & lines
|
|
270
|
+
executed = self.analysis.executed & lines
|
|
271
|
+
|
|
272
|
+
if self.analysis.has_arcs:
|
|
273
|
+
fzlines = frozenset(lines)
|
|
274
|
+
arc_possibilities_set = self.region2arc_possibilities[fzlines]
|
|
275
|
+
arcs_executed_set = self.region2arc_executed[fzlines]
|
|
276
|
+
exit_counts = self.region2exit_counts[fzlines]
|
|
277
|
+
no_branch = self.analysis.no_branch & lines
|
|
278
|
+
else:
|
|
279
|
+
arc_possibilities_set = set()
|
|
280
|
+
arcs_executed_set = set()
|
|
281
|
+
exit_counts = {}
|
|
282
|
+
no_branch = set()
|
|
283
|
+
|
|
284
|
+
return Analysis(
|
|
285
|
+
precision=self.analysis.precision,
|
|
286
|
+
filename=self.analysis.filename,
|
|
287
|
+
has_arcs=self.analysis.has_arcs,
|
|
288
|
+
statements=statements,
|
|
289
|
+
excluded=excluded,
|
|
290
|
+
executed=executed,
|
|
291
|
+
arc_possibilities_set=arc_possibilities_set,
|
|
292
|
+
arcs_executed_set=arcs_executed_set,
|
|
293
|
+
exit_counts=exit_counts,
|
|
294
|
+
no_branch=no_branch,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
246
298
|
@dataclasses.dataclass
|
|
247
299
|
class Numbers:
|
|
248
300
|
"""The numerical results of measuring coverage.
|
|
@@ -313,7 +365,7 @@ class Numbers:
|
|
|
313
365
|
|
|
314
366
|
def __radd__(self, other: int) -> Numbers:
|
|
315
367
|
# Implementing 0+Numbers allows us to sum() a list of Numbers.
|
|
316
|
-
assert other == 0
|
|
368
|
+
assert other == 0 # we only ever call it this way.
|
|
317
369
|
return self
|
|
318
370
|
|
|
319
371
|
|
|
@@ -325,14 +377,14 @@ def display_covered(pc: float, precision: int) -> str:
|
|
|
325
377
|
result in either "0" or "100".
|
|
326
378
|
|
|
327
379
|
"""
|
|
328
|
-
near0 = 1.0 / 10
|
|
380
|
+
near0 = 1.0 / 10**precision
|
|
329
381
|
if 0 < pc < near0:
|
|
330
382
|
pc = near0
|
|
331
383
|
elif (100.0 - near0) < pc < 100:
|
|
332
384
|
pc = 100.0 - near0
|
|
333
385
|
else:
|
|
334
386
|
pc = round(pc, precision)
|
|
335
|
-
return "
|
|
387
|
+
return f"{pc:.{precision}f}"
|
|
336
388
|
|
|
337
389
|
|
|
338
390
|
def _line_ranges(
|
|
@@ -344,7 +396,7 @@ def _line_ranges(
|
|
|
344
396
|
lines = sorted(lines)
|
|
345
397
|
|
|
346
398
|
pairs = []
|
|
347
|
-
start = None
|
|
399
|
+
start: TLineNo | None = None
|
|
348
400
|
lidx = 0
|
|
349
401
|
for stmt in statements:
|
|
350
402
|
if lidx >= len(lines):
|
|
@@ -390,7 +442,7 @@ def format_lines(
|
|
|
390
442
|
for line, exits in line_exits:
|
|
391
443
|
for ex in sorted(exits):
|
|
392
444
|
if line not in lines and ex not in lines:
|
|
393
|
-
dest =
|
|
445
|
+
dest = ex if ex > 0 else "exit"
|
|
394
446
|
line_items.append((line, f"{line}->{dest}"))
|
|
395
447
|
|
|
396
448
|
ret = ", ".join(t[-1] for t in sorted(line_items))
|