coverage 7.13.1__cp314-cp314t-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 (61) hide show
  1. a1_coverage.pth +1 -0
  2. coverage/__init__.py +38 -0
  3. coverage/__main__.py +12 -0
  4. coverage/annotate.py +113 -0
  5. coverage/bytecode.py +197 -0
  6. coverage/cmdline.py +1220 -0
  7. coverage/collector.py +487 -0
  8. coverage/config.py +732 -0
  9. coverage/context.py +74 -0
  10. coverage/control.py +1514 -0
  11. coverage/core.py +139 -0
  12. coverage/data.py +251 -0
  13. coverage/debug.py +669 -0
  14. coverage/disposition.py +59 -0
  15. coverage/env.py +135 -0
  16. coverage/exceptions.py +85 -0
  17. coverage/execfile.py +329 -0
  18. coverage/files.py +553 -0
  19. coverage/html.py +860 -0
  20. coverage/htmlfiles/coverage_html.js +735 -0
  21. coverage/htmlfiles/favicon_32.png +0 -0
  22. coverage/htmlfiles/index.html +199 -0
  23. coverage/htmlfiles/keybd_closed.png +0 -0
  24. coverage/htmlfiles/pyfile.html +149 -0
  25. coverage/htmlfiles/style.css +389 -0
  26. coverage/htmlfiles/style.scss +844 -0
  27. coverage/inorout.py +590 -0
  28. coverage/jsonreport.py +200 -0
  29. coverage/lcovreport.py +218 -0
  30. coverage/misc.py +381 -0
  31. coverage/multiproc.py +120 -0
  32. coverage/numbits.py +146 -0
  33. coverage/parser.py +1215 -0
  34. coverage/patch.py +118 -0
  35. coverage/phystokens.py +197 -0
  36. coverage/plugin.py +617 -0
  37. coverage/plugin_support.py +299 -0
  38. coverage/pth_file.py +16 -0
  39. coverage/py.typed +1 -0
  40. coverage/python.py +272 -0
  41. coverage/pytracer.py +370 -0
  42. coverage/regions.py +127 -0
  43. coverage/report.py +298 -0
  44. coverage/report_core.py +117 -0
  45. coverage/results.py +502 -0
  46. coverage/sqldata.py +1212 -0
  47. coverage/sqlitedb.py +226 -0
  48. coverage/sysmon.py +509 -0
  49. coverage/templite.py +319 -0
  50. coverage/tomlconfig.py +212 -0
  51. coverage/tracer.cpython-314t-aarch64-linux-musl.so +0 -0
  52. coverage/tracer.pyi +43 -0
  53. coverage/types.py +214 -0
  54. coverage/version.py +35 -0
  55. coverage/xmlreport.py +263 -0
  56. coverage-7.13.1.dist-info/METADATA +200 -0
  57. coverage-7.13.1.dist-info/RECORD +61 -0
  58. coverage-7.13.1.dist-info/WHEEL +5 -0
  59. coverage-7.13.1.dist-info/entry_points.txt +4 -0
  60. coverage-7.13.1.dist-info/licenses/LICENSE.txt +177 -0
  61. coverage-7.13.1.dist-info/top_level.txt +1 -0
coverage/types.py ADDED
@@ -0,0 +1,214 @@
1
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
+
4
+ """
5
+ Types for use throughout coverage.py.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import os
11
+ import pathlib
12
+ from collections.abc import Callable, Iterable, Mapping
13
+ from types import FrameType, ModuleType
14
+ from typing import TYPE_CHECKING, Any, Optional, Protocol
15
+
16
+ if TYPE_CHECKING:
17
+ from coverage.plugin import FileTracer
18
+
19
+
20
+ AnyCallable = Callable[..., Any]
21
+
22
+ ## File paths
23
+
24
+ # For arguments that are file paths:
25
+ FilePath = str | os.PathLike[str]
26
+ # For testing FilePath arguments
27
+ FilePathClasses = [str, pathlib.Path]
28
+ FilePathType = type[str] | type[pathlib.Path]
29
+
30
+ ## Python tracing
31
+
32
+
33
+ class TTraceFn(Protocol):
34
+ """A Python trace function."""
35
+
36
+ def __call__(
37
+ self,
38
+ frame: FrameType,
39
+ event: str,
40
+ arg: Any,
41
+ lineno: TLineNo | None = None, # Our own twist, see collector.py
42
+ ) -> TTraceFn | None: ...
43
+
44
+
45
+ ## Coverage.py tracing
46
+
47
+ # Line numbers are pervasive enough that they deserve their own type.
48
+ TLineNo = int
49
+
50
+ # Bytecode offsets are pervasive enough that they deserve their own type.
51
+ TOffset = int
52
+
53
+ TArc = tuple[TLineNo, TLineNo]
54
+
55
+
56
+ class TFileDisposition(Protocol):
57
+ """A simple value type for recording what to do with a file."""
58
+
59
+ original_filename: str
60
+ canonical_filename: str
61
+ source_filename: str | None
62
+ trace: bool
63
+ reason: str
64
+ file_tracer: FileTracer | None
65
+ has_dynamic_filename: bool
66
+
67
+
68
+ class TMatcher(Protocol):
69
+ """The shape all Matchers have."""
70
+
71
+ def match(self, s: str) -> bool:
72
+ """Does this string match?"""
73
+
74
+
75
+ # When collecting data, we use a dictionary with a few possible shapes. The
76
+ # keys are always file names.
77
+ # - If measuring line coverage, the values are sets of line numbers.
78
+ # - If measuring arcs in the Python tracer, the values are sets of arcs (pairs
79
+ # of line numbers).
80
+ # - If measuring arcs in the C tracer, the values are sets of packed arcs (two
81
+ # line numbers combined into one integer).
82
+
83
+ TTraceFileData = set[TLineNo] | set[TArc] | set[int]
84
+
85
+ TTraceData = dict[str, TTraceFileData]
86
+
87
+ # Functions passed into collectors.
88
+ TShouldTraceFn = Callable[[str, FrameType], TFileDisposition]
89
+ TCheckIncludeFn = Callable[[str, FrameType], bool]
90
+ TShouldStartContextFn = Callable[[FrameType], str | None]
91
+
92
+
93
+ class Tracer(Protocol):
94
+ """Anything that can report on Python execution."""
95
+
96
+ data: TTraceData
97
+ trace_arcs: bool
98
+ should_trace: TShouldTraceFn
99
+ should_trace_cache: Mapping[str, TFileDisposition | None]
100
+ should_start_context: TShouldStartContextFn | None
101
+ switch_context: Callable[[str | None], None] | None
102
+ lock_data: Callable[[], None]
103
+ unlock_data: Callable[[], None]
104
+ warn: TWarnFn
105
+
106
+ def __init__(self) -> None: ...
107
+
108
+ def start(self) -> TTraceFn | None:
109
+ """Start this tracer, return a trace function if based on sys.settrace."""
110
+
111
+ def stop(self) -> None:
112
+ """Stop this tracer."""
113
+
114
+ def activity(self) -> bool:
115
+ """Has there been any activity?"""
116
+
117
+ def reset_activity(self) -> None:
118
+ """Reset the activity() flag."""
119
+
120
+ def get_stats(self) -> dict[str, int] | None:
121
+ """Return a dictionary of statistics, or None."""
122
+
123
+
124
+ ## Coverage
125
+
126
+ # Many places use kwargs as Coverage kwargs.
127
+ TCovKwargs = Any
128
+
129
+
130
+ ## Configuration
131
+
132
+ # One value read from a config file.
133
+ TConfigValueIn = Optional[bool | int | float | str | Iterable[str] | Mapping[str, Iterable[str]]]
134
+ TConfigValueOut = Optional[bool | int | float | str | list[str] | dict[str, list[str]]]
135
+ # An entire config section, mapping option names to values.
136
+ TConfigSectionIn = Mapping[str, TConfigValueIn]
137
+ TConfigSectionOut = Mapping[str, TConfigValueOut]
138
+
139
+
140
+ class TConfigurable(Protocol):
141
+ """Something that can proxy to the coverage configuration settings."""
142
+
143
+ def get_option(self, option_name: str) -> TConfigValueOut | None:
144
+ """Get an option from the configuration.
145
+
146
+ `option_name` is a colon-separated string indicating the section and
147
+ option name. For example, the ``branch`` option in the ``[run]``
148
+ section of the config file would be indicated with `"run:branch"`.
149
+
150
+ Returns the value of the option.
151
+
152
+ """
153
+
154
+ def set_option(self, option_name: str, value: TConfigValueIn | TConfigSectionIn) -> None:
155
+ """Set an option in the configuration.
156
+
157
+ `option_name` is a colon-separated string indicating the section and
158
+ option name. For example, the ``branch`` option in the ``[run]``
159
+ section of the config file would be indicated with `"run:branch"`.
160
+
161
+ `value` is the new value for the option.
162
+
163
+ """
164
+
165
+
166
+ class TPluginConfig(Protocol):
167
+ """Something that can provide options to a plugin."""
168
+
169
+ def get_plugin_options(self, plugin: str) -> TConfigSectionOut:
170
+ """Get the options for a plugin."""
171
+
172
+
173
+ ## Parsing
174
+
175
+ TMorf = ModuleType | str
176
+ TMorfs = TMorf | Iterable[TMorf] | None
177
+
178
+ TSourceTokenLines = Iterable[list[tuple[str, str]]]
179
+
180
+
181
+ ## Plugins
182
+
183
+
184
+ class TPlugin(Protocol):
185
+ """What all plugins have in common."""
186
+
187
+ _coverage_plugin_name: str
188
+ _coverage_enabled: bool
189
+
190
+
191
+ ## Debugging
192
+
193
+
194
+ class TWarnFn(Protocol):
195
+ """A callable warn() function."""
196
+
197
+ def __call__(self, msg: str, slug: str | None = None, once: bool = False) -> None: ...
198
+
199
+
200
+ class TDebugCtl(Protocol):
201
+ """A DebugControl object, or something like it."""
202
+
203
+ def should(self, option: str) -> bool:
204
+ """Decide whether to output debug information in category `option`."""
205
+
206
+ def write(self, msg: str) -> None:
207
+ """Write a line of debug output."""
208
+
209
+
210
+ class TWritable(Protocol):
211
+ """Anything that can be written to."""
212
+
213
+ def write(self, msg: str) -> None:
214
+ """Write a message."""
coverage/version.py ADDED
@@ -0,0 +1,35 @@
1
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
+
4
+ """The version and URL for coverage.py"""
5
+ # This file is exec'ed in setup.py, don't import anything!
6
+
7
+ from __future__ import annotations
8
+
9
+ # version_info: same semantics as sys.version_info.
10
+ # _dev: the .devN suffix if any.
11
+ version_info = (7, 13, 1, "final", 0)
12
+ _dev = 0
13
+
14
+
15
+ def _make_version(
16
+ major: int,
17
+ minor: int,
18
+ micro: int,
19
+ releaselevel: str = "final",
20
+ serial: int = 0,
21
+ dev: int = 0,
22
+ ) -> str:
23
+ """Create a readable version string from version_info tuple components."""
24
+ assert releaselevel in ["alpha", "beta", "candidate", "final"]
25
+ version = f"{major}.{minor}.{micro}"
26
+ if releaselevel != "final":
27
+ short = {"alpha": "a", "beta": "b", "candidate": "rc"}[releaselevel]
28
+ version += f"{short}{serial}"
29
+ if dev != 0:
30
+ version += f".dev{dev}"
31
+ return version
32
+
33
+
34
+ __version__ = _make_version(*version_info, _dev)
35
+ __url__ = f"https://coverage.readthedocs.io/en/{__version__}"
coverage/xmlreport.py ADDED
@@ -0,0 +1,263 @@
1
+ # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
+ # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
+
4
+ """XML reporting for coverage.py"""
5
+
6
+ from __future__ import annotations
7
+
8
+ import os
9
+ import os.path
10
+ import sys
11
+ import time
12
+ import xml.dom.minidom
13
+ from dataclasses import dataclass
14
+ from typing import IO, TYPE_CHECKING, Any
15
+
16
+ from coverage import __version__, files
17
+ from coverage.misc import human_sorted, human_sorted_items, isolate_module
18
+ from coverage.plugin import FileReporter
19
+ from coverage.report_core import get_analysis_to_report
20
+ from coverage.results import Analysis
21
+ from coverage.types import TMorfs
22
+ from coverage.version import __url__
23
+
24
+ if TYPE_CHECKING:
25
+ from coverage import Coverage
26
+
27
+ os = isolate_module(os)
28
+
29
+
30
+ DTD_URL = "https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd"
31
+
32
+
33
+ def rate(hit: int, num: int) -> str:
34
+ """Return the fraction of `hit`/`num`, as a string."""
35
+ if num == 0:
36
+ return "1"
37
+ else:
38
+ return f"{hit / num:.4g}"
39
+
40
+
41
+ @dataclass
42
+ class PackageData:
43
+ """Data we keep about each "package" (in Java terms)."""
44
+
45
+ elements: dict[str, xml.dom.minidom.Element]
46
+ hits: int
47
+ lines: int
48
+ br_hits: int
49
+ branches: int
50
+
51
+
52
+ def appendChild(parent: Any, child: Any) -> None:
53
+ """Append a child to a parent, in a way mypy will shut up about."""
54
+ parent.appendChild(child)
55
+
56
+
57
+ class XmlReporter:
58
+ """A reporter for writing Cobertura-style XML coverage results."""
59
+
60
+ report_type = "XML report"
61
+
62
+ def __init__(self, coverage: Coverage) -> None:
63
+ self.coverage = coverage
64
+ self.config = self.coverage.config
65
+
66
+ self.source_paths = set()
67
+ if self.config.source:
68
+ for src in self.config.source:
69
+ if os.path.exists(src):
70
+ if self.config.relative_files:
71
+ src = src.rstrip(r"\/")
72
+ else:
73
+ src = files.canonical_filename(src)
74
+ self.source_paths.add(src)
75
+ self.packages: dict[str, PackageData] = {}
76
+ self.xml_out: xml.dom.minidom.Document
77
+
78
+ def report(self, morfs: TMorfs, outfile: IO[str] | None = None) -> float:
79
+ """Generate a Cobertura-compatible XML report for `morfs`.
80
+
81
+ `morfs` is a list of modules or file names.
82
+
83
+ `outfile` is a file object to write the XML to.
84
+
85
+ """
86
+ # Initial setup.
87
+ outfile = outfile or sys.stdout
88
+ has_arcs = self.coverage.get_data().has_arcs()
89
+
90
+ # Create the DOM that will store the data.
91
+ impl = xml.dom.minidom.getDOMImplementation()
92
+ assert impl is not None
93
+ self.xml_out = impl.createDocument(None, "coverage", None)
94
+
95
+ # Write header stuff.
96
+ xcoverage = self.xml_out.documentElement
97
+ assert xcoverage is not None
98
+ xcoverage.setAttribute("version", __version__)
99
+ xcoverage.setAttribute("timestamp", str(int(time.time() * 1000)))
100
+ xcoverage.appendChild(
101
+ self.xml_out.createComment(
102
+ f" Generated by coverage.py: {__url__} ",
103
+ )
104
+ )
105
+ xcoverage.appendChild(self.xml_out.createComment(f" Based on {DTD_URL} "))
106
+
107
+ # Call xml_file for each file in the data.
108
+ for fr, analysis in get_analysis_to_report(self.coverage, morfs):
109
+ self.xml_file(fr, analysis, has_arcs)
110
+
111
+ xsources = self.xml_out.createElement("sources")
112
+ xcoverage.appendChild(xsources)
113
+
114
+ # Populate the XML DOM with the source info.
115
+ for path in human_sorted(self.source_paths):
116
+ xsource = self.xml_out.createElement("source")
117
+ appendChild(xsources, xsource)
118
+ txt = self.xml_out.createTextNode(path)
119
+ appendChild(xsource, txt)
120
+
121
+ lnum_tot, lhits_tot = 0, 0
122
+ bnum_tot, bhits_tot = 0, 0
123
+
124
+ xpackages = self.xml_out.createElement("packages")
125
+ xcoverage.appendChild(xpackages)
126
+
127
+ # Populate the XML DOM with the package info.
128
+ for pkg_name, pkg_data in human_sorted_items(self.packages.items()):
129
+ xpackage = self.xml_out.createElement("package")
130
+ appendChild(xpackages, xpackage)
131
+ xclasses = self.xml_out.createElement("classes")
132
+ appendChild(xpackage, xclasses)
133
+ for _, class_elt in human_sorted_items(pkg_data.elements.items()):
134
+ appendChild(xclasses, class_elt)
135
+ xpackage.setAttribute("name", pkg_name.replace(os.sep, "."))
136
+ xpackage.setAttribute("line-rate", rate(pkg_data.hits, pkg_data.lines))
137
+ if has_arcs:
138
+ branch_rate = rate(pkg_data.br_hits, pkg_data.branches)
139
+ else:
140
+ branch_rate = "0"
141
+ xpackage.setAttribute("branch-rate", branch_rate)
142
+ xpackage.setAttribute("complexity", "0")
143
+
144
+ lhits_tot += pkg_data.hits
145
+ lnum_tot += pkg_data.lines
146
+ bhits_tot += pkg_data.br_hits
147
+ bnum_tot += pkg_data.branches
148
+
149
+ xcoverage.setAttribute("lines-valid", str(lnum_tot))
150
+ xcoverage.setAttribute("lines-covered", str(lhits_tot))
151
+ xcoverage.setAttribute("line-rate", rate(lhits_tot, lnum_tot))
152
+ if has_arcs:
153
+ xcoverage.setAttribute("branches-valid", str(bnum_tot))
154
+ xcoverage.setAttribute("branches-covered", str(bhits_tot))
155
+ xcoverage.setAttribute("branch-rate", rate(bhits_tot, bnum_tot))
156
+ else:
157
+ xcoverage.setAttribute("branches-covered", "0")
158
+ xcoverage.setAttribute("branches-valid", "0")
159
+ xcoverage.setAttribute("branch-rate", "0")
160
+ xcoverage.setAttribute("complexity", "0")
161
+
162
+ # Write the output file.
163
+ outfile.write(serialize_xml(self.xml_out))
164
+
165
+ # Return the total percentage.
166
+ denom = lnum_tot + bnum_tot
167
+ if denom == 0:
168
+ pct = 0.0
169
+ else:
170
+ pct = 100.0 * (lhits_tot + bhits_tot) / denom
171
+ return pct
172
+
173
+ def xml_file(self, fr: FileReporter, analysis: Analysis, has_arcs: bool) -> None:
174
+ """Add to the XML report for a single file."""
175
+
176
+ if self.config.skip_empty:
177
+ if analysis.numbers.n_statements == 0:
178
+ return
179
+
180
+ # Create the "lines" and "package" XML elements, which
181
+ # are populated later. Note that a package == a directory.
182
+ filename = fr.filename.replace("\\", "/")
183
+ for source_path in self.source_paths:
184
+ if not self.config.relative_files:
185
+ source_path = files.canonical_filename(source_path)
186
+ if filename.startswith(source_path.replace("\\", "/") + "/"):
187
+ rel_name = filename[len(source_path) + 1 :]
188
+ break
189
+ else:
190
+ rel_name = fr.relative_filename().replace("\\", "/")
191
+ self.source_paths.add(fr.filename[: -len(rel_name)].rstrip(r"\/"))
192
+
193
+ dirname = os.path.dirname(rel_name) or "."
194
+ dirname = "/".join(dirname.split("/")[: self.config.xml_package_depth])
195
+ package_name = dirname.replace("/", ".")
196
+
197
+ package = self.packages.setdefault(package_name, PackageData({}, 0, 0, 0, 0))
198
+
199
+ xclass: xml.dom.minidom.Element = self.xml_out.createElement("class")
200
+
201
+ appendChild(xclass, self.xml_out.createElement("methods"))
202
+
203
+ xlines = self.xml_out.createElement("lines")
204
+ appendChild(xclass, xlines)
205
+
206
+ xclass.setAttribute("name", os.path.relpath(rel_name, dirname))
207
+ xclass.setAttribute("filename", rel_name.replace("\\", "/"))
208
+ xclass.setAttribute("complexity", "0")
209
+
210
+ branch_stats = analysis.branch_stats()
211
+ missing_branch_arcs = analysis.missing_branch_arcs()
212
+
213
+ # For each statement, create an XML "line" element.
214
+ for line in sorted(analysis.statements):
215
+ xline = self.xml_out.createElement("line")
216
+ xline.setAttribute("number", str(line))
217
+
218
+ # Q: can we get info about the number of times a statement is
219
+ # executed? If so, that should be recorded here.
220
+ xline.setAttribute("hits", str(int(line not in analysis.missing)))
221
+
222
+ if has_arcs:
223
+ if line in branch_stats:
224
+ total, taken = branch_stats[line]
225
+ xline.setAttribute("branch", "true")
226
+ xline.setAttribute(
227
+ "condition-coverage",
228
+ f"{100 * taken // total}% ({taken}/{total})",
229
+ )
230
+ if line in missing_branch_arcs:
231
+ annlines = ["exit" if b < 0 else str(b) for b in missing_branch_arcs[line]]
232
+ xline.setAttribute("missing-branches", ",".join(annlines))
233
+ appendChild(xlines, xline)
234
+
235
+ class_lines = len(analysis.statements)
236
+ class_hits = class_lines - len(analysis.missing)
237
+
238
+ if has_arcs:
239
+ class_branches = sum(t for t, k in branch_stats.values())
240
+ missing_branches = sum(t - k for t, k in branch_stats.values())
241
+ class_br_hits = class_branches - missing_branches
242
+ else:
243
+ class_branches = 0
244
+ class_br_hits = 0
245
+
246
+ # Finalize the statistics that are collected in the XML DOM.
247
+ xclass.setAttribute("line-rate", rate(class_hits, class_lines))
248
+ if has_arcs:
249
+ branch_rate = rate(class_br_hits, class_branches)
250
+ else:
251
+ branch_rate = "0"
252
+ xclass.setAttribute("branch-rate", branch_rate)
253
+
254
+ package.elements[rel_name] = xclass
255
+ package.hits += class_hits
256
+ package.lines += class_lines
257
+ package.br_hits += class_br_hits
258
+ package.branches += class_branches
259
+
260
+
261
+ def serialize_xml(dom: xml.dom.minidom.Document) -> str:
262
+ """Serialize a minidom node to XML."""
263
+ return dom.toprettyxml()