Skip to content

COVERAGE_CORE=sysmon now produces an error for python3.12 #2076

@Sillocan

Description

@Sillocan

Describe the bug

With v7.11.1 of coverage-py and python3.12, what was previously a warning is now an exception. I was surprised to see this happen on a bugfix, rather than a breaking change. I'm mostly reporting this for other users that might be having a similar issue.

We use COVERAGE_CORE=sysmon to account for a performance issue between python versions. This produced a warning that we were able to suppress, as we were fine with ignoring for older versions of python. Now with v7.11.1 this is an exception we can't ignore. See: #1812 (comment) for similar comments to ours.

Before:

/usr/local/lib/python3.12/site-packages/coverage/core.py:81: CoverageWarning: sys.monitoring can't measure branches in this version, using default core (no-sysmon); see https://coverage.readthedocs.io/en/7.11.0/messages.html#warning-no-sysmon
  warn(f"sys.monitoring {reason_no_sysmon}, using default core", slug="no-sysmon")

Now:

  File "/usr/local/lib/python3.12/site-packages/coverage/core.py", line 94, in __init__
    raise ConfigError(
coverage.exceptions.ConfigError: Can't use core=sysmon: sys.monitoring can't measure branches in this version

To Reproduce

Make a project with python_version = '==3.12', coverage==7.11.1, pytest, and pytest-cov. Then run pytest. I've put a script below to make a small example.

#!/bin/bash

# Create directory structure
mkdir -p "testpackage/src/testpackage"
mkdir -p "testpackage/tests"

# Create pyproject.toml
cat > "testpackage/pyproject.toml" << 'EOF'
[project]
name = "testpackage"
version = "0.1.0"
description = "Add your description here"
requires-python = "==3.12"
dependencies = [
    "pytest==8.4.2",
    "coverage==7.11.0",
    "pytest-cov==7.0.0",
]

[build-system]
requires = ["uv_build>=0.9.7,<0.10.0"]
build-backend = "uv_build"

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
    "--cov=testpackage",
    "--cov-report=html",
    "--cov-report=term-missing",
]

[tool.coverage.run]
source = ["src"]
branch = true
core = "sysmon"

EOF

# Create src/testpackage/__init__.py
cat > "testpackage/src/testpackage/__init__.py" << 'EOF'
def main() -> None:
    print("Hello from testpackage!")

def add_numbers(a, b):
    """Simple function to add two numbers."""
    return a + b
EOF

# Create tests/test_example.py
cat > "testpackage/tests/test_example.py" << 'EOF'
"""
Example pytest test file demonstrating basic testing patterns.
"""
import pytest
from testpackage import add_numbers


def test_add_positive_numbers():
    """Test adding positive numbers."""
    result = add_numbers(2, 3)
    assert result == 5
EOF

cd testpackage

uv run pytest # <-- observe no error
uv add coverage==7.11.1
uv run pytest # <-- observe error

The first run outputs:

================================================================================== test session starts ===================================================================================
platform linux -- Python 3.12.0, pytest-8.4.2, pluggy-1.6.0
rootdir: /tmp/testpackage
configfile: pyproject.toml
testpaths: tests
plugins: cov-7.0.0
collected 1 item                                                                                                                                                                         

tests/test_example.py .                                                                                                                                                            [100%]

==================================================================================== warnings summary ====================================================================================

The second test outputs

Traceback (most recent call last):
  File "/tmp/testpackage/.venv/bin/pytest", line 10, in <module>
    sys.exit(console_main())
             ^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 201, in console_main
    code = main()
           ^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 156, in main
    config = _prepareconfig(args, plugins)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 342, in _prepareconfig
    config = pluginmanager.hook.pytest_cmdline_parse(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 512, in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 167, in _multicall
    raise exception
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
    teardown.throw(exception)
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/helpconfig.py", line 112, in pytest_cmdline_parse
    config = yield
             ^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 121, in _multicall
    res = hook_impl.function(*args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1146, in pytest_cmdline_parse
    self.parse(args)
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1527, in parse
    self._preparse(args, addopts=addopts)
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1431, in _preparse
    self.hook.pytest_load_initial_conftests(
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 512, in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 167, in _multicall
    raise exception
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
    teardown.throw(exception)
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/warnings.py", line 129, in pytest_load_initial_conftests
    return (yield)
            ^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
    teardown.throw(exception)
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/_pytest/capture.py", line 173, in pytest_load_initial_conftests
    yield
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 121, in _multicall
    res = hook_impl.function(*args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pytest_cov/plugin.py", line 200, in pytest_load_initial_conftests
    plugin = CovPlugin(options, early_config.pluginmanager)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pytest_cov/plugin.py", line 250, in __init__
    self.start(engine.Central)
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pytest_cov/plugin.py", line 263, in start
    self.cov_controller.start()
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pytest_cov/engine.py", line 55, in ensure_topdir_wrapper
    return meth(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/pytest_cov/engine.py", line 284, in start
    self.cov.start()
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/coverage/control.py", line 694, in start
    self._init_for_start()
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/coverage/control.py", line 586, in _init_for_start
    self._core = Core(
                 ^^^^^
  File "/tmp/testpackage/.venv/lib/python3.12/site-packages/coverage/core.py", line 94, in __init__
    raise ConfigError(
coverage.exceptions.ConfigError: Can't use core=sysmon: sys.monitoring can't measure branches in this version

Expected behavior

Warning to occur and to fallback to core

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions