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