Skip to content

Commit 2e88d42

Browse files
committed
feat: sys.monitoring, switch from BRANCH_TAKEN to BRANCH_RIGHT
Now branch measurement should be fast on 3.14.0a5+. It is still not a default core, but we might be getting close.
1 parent 3418eb9 commit 2e88d42

17 files changed

+375
-174
lines changed

CHANGES.rst

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ Unreleased
2828
with one path not taken. Now it is understood as always true and no coverage
2929
is missing.
3030

31+
- The experimental sys.monitoring support should now work for branch coverage
32+
if you are using Python newer than 3.14.0 alpha 5. This should greatly
33+
reduce the overhead coverage.py imposes on your test suite. Set the
34+
environment variable ``COVERAGE_CORE=sysmon`` to try it out.
35+
3136
- The :class:`Coverage constructor<.Coverage>` now has a ``plugins`` parameter
3237
for passing in plugin objects directly, thanks to `Alex Gaynor <pull
3338
1919_>`_.

coverage/control.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,8 @@ def _init_for_start(self) -> None:
548548

549549
self._core = Core(
550550
warn=self._warn,
551-
timid=self.config.timid,
551+
config=self.config,
552+
dynamic_contexts=(should_start_context is not None),
552553
metacov=self._metacov,
553554
)
554555
self._collector = Collector(

coverage/core.py

+32-20
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@
1010
from typing import Any
1111

1212
from coverage import env
13+
from coverage.config import CoverageConfig
1314
from coverage.disposition import FileDisposition
1415
from coverage.exceptions import ConfigError
1516
from coverage.misc import isolate_module
1617
from coverage.pytracer import PyTracer
1718
from coverage.sysmon import SysMonitor
1819
from coverage.types import (
1920
TFileDisposition,
20-
Tracer,
2121
TWarnFn,
22+
Tracer,
2223
)
2324

2425

@@ -52,36 +53,47 @@ class Core:
5253
packed_arcs: bool
5354
systrace: bool
5455

55-
def __init__(self,
56+
def __init__(
57+
self,
5658
warn: TWarnFn,
57-
timid: bool,
59+
config: CoverageConfig,
60+
dynamic_contexts: bool,
5861
metacov: bool,
5962
) -> None:
60-
# Defaults
61-
self.tracer_kwargs = {}
63+
# Check the conditions that preclude us from using sys.monitoring.
64+
reason_no_sysmon = ""
65+
if not env.PYBEHAVIOR.pep669:
66+
reason_no_sysmon = "isn't available in this version"
67+
elif config.branch and not env.PYBEHAVIOR.branch_right_left:
68+
reason_no_sysmon = "can't measure branches in this version"
69+
elif dynamic_contexts:
70+
reason_no_sysmon = "doesn't yet support dynamic contexts"
6271

63-
core_name: str | None
64-
if timid:
72+
core_name: str | None = None
73+
if config.timid:
6574
core_name = "pytrace"
66-
else:
75+
76+
if core_name is None:
6777
core_name = os.getenv("COVERAGE_CORE")
6878

69-
if core_name == "sysmon" and not env.PYBEHAVIOR.pep669:
70-
warn("sys.monitoring isn't available, using default core", slug="no-sysmon")
71-
core_name = None
79+
if core_name == "sysmon" and reason_no_sysmon:
80+
warn(f"sys.monitoring {reason_no_sysmon}, using default core", slug="no-sysmon")
81+
core_name = None
82+
83+
if core_name is None:
84+
# Someday we will default to sysmon, but it's still experimental:
85+
# if not reason_no_sysmon:
86+
# core_name = "sysmon"
87+
if HAS_CTRACER:
88+
core_name = "ctrace"
89+
else:
90+
core_name = "pytrace"
7291

73-
if not core_name:
74-
# Once we're comfortable with sysmon as a default:
75-
# if env.PYBEHAVIOR.pep669 and self.should_start_context is None:
76-
# core_name = "sysmon"
77-
if HAS_CTRACER:
78-
core_name = "ctrace"
79-
else:
80-
core_name = "pytrace"
92+
self.tracer_kwargs = {}
8193

8294
if core_name == "sysmon":
8395
self.tracer_class = SysMonitor
84-
self.tracer_kwargs = {"tool_id": 3 if metacov else 1}
96+
self.tracer_kwargs["tool_id"] = 3 if metacov else 1
8597
self.file_disposition_class = FileDisposition
8698
self.supports_plugins = False
8799
self.packed_arcs = False

coverage/env.py

+5
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ class PYBEHAVIOR:
156156
# PEP649 and PEP749: Deferred annotations
157157
deferred_annotations = (PYVERSION >= (3, 14))
158158

159+
# Does sys.monitoring support BRANCH_RIGHT and BRANCH_LEFT? The names
160+
# were added in early 3.14 alphas, but didn't work entirely correctly until
161+
# after 3.14.0a5.
162+
branch_right_left = (pep669 and (PYVERSION > (3, 14, 0, "alpha", 5, 0)))
163+
159164

160165
# Coverage.py specifics, about testing scenarios. See tests/testenv.py also.
161166

0 commit comments

Comments
 (0)