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.
Files changed (54) hide show
  1. coverage/__init__.py +2 -0
  2. coverage/__main__.py +2 -0
  3. coverage/annotate.py +1 -2
  4. coverage/bytecode.py +177 -3
  5. coverage/cmdline.py +329 -154
  6. coverage/collector.py +31 -42
  7. coverage/config.py +166 -62
  8. coverage/context.py +4 -5
  9. coverage/control.py +164 -85
  10. coverage/core.py +70 -33
  11. coverage/data.py +3 -4
  12. coverage/debug.py +112 -56
  13. coverage/disposition.py +1 -0
  14. coverage/env.py +65 -55
  15. coverage/exceptions.py +35 -7
  16. coverage/execfile.py +18 -13
  17. coverage/files.py +23 -18
  18. coverage/html.py +134 -88
  19. coverage/htmlfiles/style.css +42 -2
  20. coverage/htmlfiles/style.scss +65 -1
  21. coverage/inorout.py +61 -44
  22. coverage/jsonreport.py +17 -8
  23. coverage/lcovreport.py +16 -20
  24. coverage/misc.py +50 -46
  25. coverage/multiproc.py +12 -7
  26. coverage/numbits.py +3 -4
  27. coverage/parser.py +193 -269
  28. coverage/patch.py +166 -0
  29. coverage/phystokens.py +24 -25
  30. coverage/plugin.py +13 -13
  31. coverage/plugin_support.py +36 -35
  32. coverage/python.py +9 -13
  33. coverage/pytracer.py +40 -33
  34. coverage/regions.py +2 -1
  35. coverage/report.py +59 -43
  36. coverage/report_core.py +6 -9
  37. coverage/results.py +118 -66
  38. coverage/sqldata.py +260 -210
  39. coverage/sqlitedb.py +33 -25
  40. coverage/sysmon.py +195 -157
  41. coverage/templite.py +6 -6
  42. coverage/tomlconfig.py +12 -12
  43. coverage/tracer.cp311-win_amd64.pyd +0 -0
  44. coverage/tracer.pyi +2 -0
  45. coverage/types.py +25 -22
  46. coverage/version.py +3 -18
  47. coverage/xmlreport.py +16 -13
  48. {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info}/METADATA +40 -18
  49. coverage-7.11.1.dist-info/RECORD +59 -0
  50. {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info}/WHEEL +1 -1
  51. coverage-7.6.7.dist-info/RECORD +0 -58
  52. {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info}/entry_points.txt +0 -0
  53. {coverage-7.6.7.dist-info → coverage-7.11.1.dist-info/licenses}/LICENSE.txt +0 -0
  54. {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 for p in self.arc_possibilities
181
- if p not in self.arcs_executed
182
- and p[0] not in self.no_branch
183
- and p[1] not in self.excluded
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
- if l1 == l2:
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
- if l1 == l2:
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 # we only ever call it this way.
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 ** precision
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 "%.*f" % (precision, pc)
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 = (ex if ex > 0 else "exit")
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))