Skip to content

Commit c5760c3

Browse files
committed
feat: core can be specified in the config file. #1746
1 parent 66e4f8d commit c5760c3

File tree

6 files changed

+58
-3
lines changed

6 files changed

+58
-3
lines changed

CHANGES.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ Unreleased
2727
PYTHONWARNDEFAULTENCODING, fixing `issue 1966`_. Thanks, `Henry Schreiner
2828
<pull 1967_>`_.
2929

30+
- Added a ``[run] core`` configuration setting to specify the measurement core,
31+
which was previously only available through the COVERAGE_CORE environment
32+
variable. Finishes `issue 1746`_.
33+
34+
.. _issue 1746: https://github.com/nedbat/coveragepy/issues/1746
3035
.. _issue 1966: https://github.com/nedbat/coveragepy/issues/1966
3136
.. _pull 1967: https://github.com/nedbat/coveragepy/pull/1967
3237

coverage/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ def __init__(self) -> None:
197197
self.command_line: str | None = None
198198
self.concurrency: list[str] = []
199199
self.context: str | None = None
200+
self.core: str | None = None
200201
self.cover_pylib = False
201202
self.data_file = ".coverage"
202203
self.debug: list[str] = []
@@ -379,6 +380,7 @@ def copy(self) -> CoverageConfig:
379380
("command_line", "run:command_line"),
380381
("concurrency", "run:concurrency", "list"),
381382
("context", "run:context"),
383+
("core", "run:core"),
382384
("cover_pylib", "run:cover_pylib", "boolean"),
383385
("data_file", "run:data_file"),
384386
("debug", "run:debug", "list"),
@@ -621,6 +623,10 @@ def read_coverage_config(
621623
debugs = os.getenv("COVERAGE_DEBUG")
622624
if debugs:
623625
config.debug.extend(d.strip() for d in debugs.split(","))
626+
# Read the COVERAGE_CORE environment variable for backward compatibility.
627+
env_core = os.getenv("COVERAGE_CORE")
628+
if env_core:
629+
config.core = env_core
624630

625631
# 4) from constructor arguments:
626632
config.from_args(**kwargs)

coverage/core.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
CTRACER_FILE: str | None = coverage.tracer.__file__
3232
except ImportError:
3333
# Couldn't import the C extension, maybe it isn't built.
34+
# We still need to check the environment variable directly here,
35+
# as this code runs before configuration is loaded.
3436
if os.getenv("COVERAGE_CORE") == "ctrace": # pragma: part covered
3537
# During testing, we use the COVERAGE_CORE environment variable
3638
# to indicate that we've fiddled with the environment to test this
@@ -74,7 +76,7 @@ def __init__(
7476
core_name = "pytrace"
7577

7678
if core_name is None:
77-
core_name = os.getenv("COVERAGE_CORE")
79+
core_name = config.core
7880

7981
if core_name == "sysmon" and reason_no_sysmon:
8082
warn(f"sys.monitoring {reason_no_sysmon}, using default core", slug="no-sysmon")

doc/cmd.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,9 @@ simpler but slower trace method, and might be needed in rare cases.
204204

205205
In Python 3.12 and above, you can try an experimental core based on the new
206206
:mod:`sys.monitoring <python:sys.monitoring>` module by defining a
207-
``COVERAGE_CORE=sysmon`` environment variable. This should be faster, though
208-
plugins and dynamic contexts are not yet supported with it.
207+
``COVERAGE_CORE=sysmon`` environment variable or by setting ``core = sysmon``
208+
in the configuration file. This should be faster, though plugins and
209+
dynamic contexts are not yet supported with it.
209210

210211
Coverage.py sets an environment variable, ``COVERAGE_RUN`` to indicate that
211212
your code is running under coverage measurement. The value is not relevant,

doc/config.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,23 @@ Before version 4.2, this option only accepted a single string.
330330

331331
.. _config_run_cover_pylib:
332332

333+
.. _config_run_core:
334+
335+
[run] core
336+
................
337+
338+
(string) Specify which trace function implementation to use. Valid values are:
339+
"pytrace" for the pure Python implementation, "ctrace" for the C implementation
340+
(default), or "sysmon" for the :mod:`sys.monitoring <python:sys.monitoring>`
341+
implementation (Python 3.12+ only).
342+
343+
This was previously only available as the COVERAGE_CORE environment variable.
344+
Note that the "sysmon" core is experimental and does not yet support plugins
345+
or dynamic contexts.
346+
347+
.. versionadded:: 7.9
348+
349+
333350
[run] cover_pylib
334351
.................
335352

tests/test_config.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,30 @@ def test_exclude_also(self) -> None:
491491
expected = coverage.config.DEFAULT_EXCLUDE + ["foobar", "raise .*Error"]
492492
assert cov.config.exclude_list == expected
493493

494+
def test_core_option(self) -> None:
495+
# Test that the core option can be set in the configuration file
496+
self.make_file(".coveragerc", """\
497+
[run]
498+
core = pytrace
499+
""")
500+
501+
# Skip calling Coverage() which would actually initialize the tracer
502+
# and instead manually initialize the config
503+
from coverage.config import CoverageConfig
504+
config = CoverageConfig()
505+
config.from_file(".coveragerc", lambda m: None, our_file=True)
506+
assert config.core == "pytrace"
507+
508+
# Test with TOML config file
509+
self.make_file("pyproject.toml", """\
510+
[tool.coverage.run]
511+
core = "ctrace"
512+
""")
513+
514+
config = CoverageConfig()
515+
config.from_file("pyproject.toml", lambda m: None, our_file=True)
516+
assert config.core == "ctrace"
517+
494518

495519
class ConfigFileTest(UsingModulesMixin, CoverageTest):
496520
"""Tests of the config file settings in particular."""

0 commit comments

Comments
 (0)