coverage 7.6.10__cp312-cp312-musllinux_1_2_aarch64.whl → 7.12.0__cp312-cp312-musllinux_1_2_aarch64.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 (57) hide show
  1. coverage/__init__.py +3 -1
  2. coverage/__main__.py +3 -1
  3. coverage/annotate.py +2 -3
  4. coverage/bytecode.py +178 -4
  5. coverage/cmdline.py +330 -155
  6. coverage/collector.py +32 -43
  7. coverage/config.py +167 -63
  8. coverage/context.py +5 -6
  9. coverage/control.py +165 -86
  10. coverage/core.py +71 -34
  11. coverage/data.py +4 -5
  12. coverage/debug.py +113 -57
  13. coverage/disposition.py +2 -1
  14. coverage/env.py +29 -78
  15. coverage/exceptions.py +29 -7
  16. coverage/execfile.py +19 -14
  17. coverage/files.py +24 -19
  18. coverage/html.py +118 -75
  19. coverage/htmlfiles/coverage_html.js +12 -10
  20. coverage/htmlfiles/index.html +45 -10
  21. coverage/htmlfiles/pyfile.html +2 -2
  22. coverage/htmlfiles/style.css +54 -6
  23. coverage/htmlfiles/style.scss +85 -3
  24. coverage/inorout.py +62 -45
  25. coverage/jsonreport.py +22 -9
  26. coverage/lcovreport.py +16 -18
  27. coverage/misc.py +51 -47
  28. coverage/multiproc.py +12 -7
  29. coverage/numbits.py +4 -5
  30. coverage/parser.py +150 -251
  31. coverage/patch.py +166 -0
  32. coverage/phystokens.py +25 -26
  33. coverage/plugin.py +14 -14
  34. coverage/plugin_support.py +37 -36
  35. coverage/python.py +13 -14
  36. coverage/pytracer.py +31 -33
  37. coverage/regions.py +3 -2
  38. coverage/report.py +60 -44
  39. coverage/report_core.py +7 -10
  40. coverage/results.py +152 -68
  41. coverage/sqldata.py +261 -211
  42. coverage/sqlitedb.py +37 -29
  43. coverage/sysmon.py +237 -162
  44. coverage/templite.py +19 -7
  45. coverage/tomlconfig.py +13 -13
  46. coverage/tracer.cpython-312-aarch64-linux-musl.so +0 -0
  47. coverage/tracer.pyi +3 -1
  48. coverage/types.py +26 -23
  49. coverage/version.py +4 -19
  50. coverage/xmlreport.py +17 -14
  51. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info}/METADATA +50 -28
  52. coverage-7.12.0.dist-info/RECORD +59 -0
  53. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info}/WHEEL +1 -1
  54. coverage-7.6.10.dist-info/RECORD +0 -58
  55. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info}/entry_points.txt +0 -0
  56. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info/licenses}/LICENSE.txt +0 -0
  57. {coverage-7.6.10.dist-info → coverage-7.12.0.dist-info}/top_level.txt +0 -0
coverage/pytracer.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
- # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
3
 
4
4
  """Raw data collector for coverage.py."""
5
5
 
@@ -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,20 +18,19 @@ 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
 
31
-
32
30
  # I don't understand why, but if we use `cast(set[TLineNo], ...)` inside
33
31
  # the _trace() function, we get some strange behavior on PyPy 3.10.
34
32
  # Assigning these names here and using them below fixes the problem.
35
- # See https://github.com/nedbat/coveragepy/issues/1902
33
+ # See https://github.com/coveragepy/coveragepy/issues/1902
36
34
  set_TLineNo = set[TLineNo]
37
35
  set_TArc = set[TArc]
38
36
 
@@ -53,6 +51,7 @@ else:
53
51
 
54
52
  THIS_FILE = __file__.rstrip("co")
55
53
 
54
+
56
55
  class PyTracer(Tracer):
57
56
  """Python implementation of the raw data tracer."""
58
57
 
@@ -126,19 +125,20 @@ class PyTracer(Tracer):
126
125
 
127
126
  def log(self, marker: str, *args: Any) -> None:
128
127
  """For hard-core logging of what this tracer is doing."""
129
- with open("/tmp/debug_trace.txt", "a") as f:
128
+ with open("/tmp/debug_trace.txt", "a", encoding="utf-8") as f:
130
129
  f.write(f"{marker} {self.id}[{len(self.data_stack)}]")
131
- if 0: # if you want thread ids..
132
- f.write(".{:x}.{:x}".format( # type: ignore[unreachable]
133
- self.thread.ident,
134
- self.threading.current_thread().ident,
135
- ))
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
+ )
136
137
  f.write(" {}".format(" ".join(map(str, args))))
137
- if 0: # if you want callers..
138
- f.write(" | ") # type: ignore[unreachable]
138
+ if 0: # if you want callers..
139
+ f.write(" | ") # type: ignore[unreachable]
139
140
  stack = " / ".join(
140
- (fname or "???").rpartition("/")[-1]
141
- for _, fname, _, _ in self.data_stack
141
+ (fname or "???").rpartition("/")[-1] for _, fname, _, _ in self.data_stack
142
142
  )
143
143
  f.write(stack)
144
144
  f.write("\n")
@@ -147,8 +147,8 @@ class PyTracer(Tracer):
147
147
  self,
148
148
  frame: FrameType,
149
149
  event: str,
150
- arg: Any, # pylint: disable=unused-argument
151
- lineno: TLineNo | None = None, # pylint: disable=unused-argument
150
+ arg: Any, # pylint: disable=unused-argument
151
+ lineno: TLineNo | None = None, # pylint: disable=unused-argument
152
152
  ) -> TTraceFn | None:
153
153
  """The trace function passed to sys.settrace."""
154
154
 
@@ -158,11 +158,11 @@ class PyTracer(Tracer):
158
158
  # f = frame; code = f.f_code
159
159
  # self.log(":", f"{code.co_filename} {f.f_lineno} {code.co_name}()", event)
160
160
 
161
- if (self.stopped and sys.gettrace() == self._cached_bound_method_trace): # pylint: disable=comparison-with-callable
161
+ if self.stopped and sys.gettrace() == self._cached_bound_method_trace: # pylint: disable=comparison-with-callable
162
162
  # The PyTrace.stop() method has been called, possibly by another
163
163
  # thread, let's deactivate ourselves now.
164
164
  if 0:
165
- f = frame # type: ignore[unreachable]
165
+ f = frame # type: ignore[unreachable]
166
166
  self.log("---\nX", f.f_code.co_filename, f.f_lineno)
167
167
  while f:
168
168
  self.log(">", f.f_code.co_filename, f.f_lineno, f.f_code.co_name, f.f_trace)
@@ -187,12 +187,12 @@ class PyTracer(Tracer):
187
187
  if event == "call":
188
188
  # Should we start a new context?
189
189
  if self.should_start_context and self.context is None:
190
- context_maybe = self.should_start_context(frame) # pylint: disable=not-callable
190
+ context_maybe = self.should_start_context(frame) # pylint: disable=not-callable
191
191
  if context_maybe is not None:
192
192
  self.context = context_maybe
193
193
  started_context = True
194
194
  assert self.switch_context is not None
195
- self.switch_context(self.context) # pylint: disable=not-callable
195
+ self.switch_context(self.context) # pylint: disable=not-callable
196
196
  else:
197
197
  started_context = False
198
198
  else:
@@ -248,9 +248,9 @@ class PyTracer(Tracer):
248
248
  # The current opcode is guaranteed to be RESUME. The argument
249
249
  # determines what kind of resume it is.
250
250
  oparg = frame.f_code.co_code[frame.f_lasti + 1]
251
- real_call = (oparg == 0)
251
+ real_call = (oparg == 0) # fmt: skip
252
252
  else:
253
- real_call = (getattr(frame, "f_lasti", -1) < 0)
253
+ real_call = (getattr(frame, "f_lasti", -1) < 0) # fmt: skip
254
254
  if real_call:
255
255
  self.last_line = -frame.f_code.co_firstlineno
256
256
  else:
@@ -281,7 +281,7 @@ class PyTracer(Tracer):
281
281
  # It is a real return if we aren't going to resume next.
282
282
  if env.PYBEHAVIOR.lasti_is_yield:
283
283
  lasti += 2
284
- real_return = (code[lasti] != RESUME)
284
+ real_return = code[lasti] != RESUME
285
285
  else:
286
286
  if code[lasti] == RETURN_VALUE:
287
287
  real_return = True
@@ -305,7 +305,8 @@ class PyTracer(Tracer):
305
305
  if self.started_context:
306
306
  assert self.switch_context is not None
307
307
  self.context = None
308
- self.switch_context(None) # pylint: disable=not-callable
308
+ self.switch_context(None) # pylint: disable=not-callable
309
+
309
310
  return self._cached_bound_method_trace
310
311
 
311
312
  def start(self) -> TTraceFn:
@@ -339,22 +340,19 @@ class PyTracer(Tracer):
339
340
  # Called on a different thread than started us: we can't unhook
340
341
  # ourselves, but we've set the flag that we should stop, so we
341
342
  # won't do any more tracing.
342
- #self.log("~", "stopping on different threads")
343
+ # self.log("~", "stopping on different threads")
343
344
  return
344
345
 
345
346
  # PyPy clears the trace function before running atexit functions,
346
347
  # so don't warn if we are in atexit on PyPy and the trace function
347
348
  # has changed to None. Metacoverage also messes this up, so don't
348
349
  # warn if we are measuring ourselves.
349
- suppress_warning = (
350
- (env.PYPY and self.in_atexit and tf is None)
351
- or env.METACOV
352
- )
350
+ suppress_warning = (env.PYPY and self.in_atexit and tf is None) or env.METACOV
353
351
  if self.warn and not suppress_warning:
354
- if tf != self._cached_bound_method_trace: # pylint: disable=comparison-with-callable
352
+ if tf != self._cached_bound_method_trace: # pylint: disable=comparison-with-callable
355
353
  self.warn(
356
- "Trace function changed, data is likely wrong: " +
357
- 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}",
358
356
  slug="trace-changed",
359
357
  )
360
358
 
coverage/regions.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
- # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
3
 
4
4
  """Find functions and classes in Python code."""
5
5
 
@@ -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
@@ -1,17 +1,16 @@
1
1
  # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
- # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
3
 
4
4
  """Summary reporting"""
5
5
 
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.fr_analysis: list[tuple[FileReporter, Analysis]] = []
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 _report_text(
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
- formats.update(dict(Cover="{:>{n}}%"), Missing=" {:9}")
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
- # build string with line values
92
- line_items = [
93
- formats[item].format(str(value),
94
- name_len=max_name, n=max_n-1) for item, value in zip(header, values)
95
- ]
96
- self.write_items(line_items)
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
- line_items = [
103
- formats[item].format(str(value),
104
- name_len=max_name, n=max_n-1) for item, value in zip(header, total_line)
105
- ]
106
- self.write_items(line_items)
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 _report_markdown(
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(["- |".rjust(len(header_items[0])-1, "-")] +
142
- ["-: |".rjust(len(item)-1, "-") for item in header_items[1:]],
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
- # build string with line values
151
- formats.update(dict(Cover="{:>{n}}% |"))
152
- line_items = [
153
- formats[item].format(str(value).replace("_", "\\_"), name_len=max_name, n=max_n-1)
154
- for item, value in zip(header, values)
155
- ]
156
- self.write_items(line_items)
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(dict(Name="|{:>{name_len}} |", Cover="{:>{n}} |"))
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 (fr, analysis) in self.fr_analysis:
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
- file_suffix = "s" if self.skipped_count>1 else ""
270
+ files = plural(self.skipped_count, "file")
255
271
  end_lines.append(
256
- f"\n{self.skipped_count} file{file_suffix} skipped due to complete coverage.",
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
- file_suffix = "s" if self.empty_count > 1 else ""
260
- end_lines.append(f"\n{self.empty_count} empty file{file_suffix} skipped.")
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._report_markdown
279
+ formatter = self.report_markdown
264
280
  else:
265
- formatter = self._report_text
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.fr_analysis.append((fr, analysis))
298
+ self.fr_analyses.append((fr, analysis))
coverage/report_core.py CHANGED
@@ -1,19 +1,16 @@
1
1
  # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
- # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
3
 
4
4
  """Reporter foundation for coverage.py."""
5
5
 
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 prep_patterns, GlobMatcher
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) # pragma: part covered (doesn't return)
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
- ) -> Iterator[tuple[FileReporter, Analysis]]:
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(): # type: ignore[attr-defined]
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")