From 9f0753bdddd14cd90856d610407262b57f663f24 Mon Sep 17 00:00:00 2001
From: Ned Batchelder
Date: Sat, 8 Nov 2025 13:18:09 -0500
Subject: [PATCH 1/5] fix: not-python files shouldn't stop measurement. #2077
---
CHANGES.rst | 7 ++++++-
coverage/core.py | 3 +++
coverage/sysmon.py | 10 +++++++++-
tests/test_arcs.py | 22 ++++++++++++++++++++++
4 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/CHANGES.rst b/CHANGES.rst
index a22628bfd..b4e53cdcf 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -23,7 +23,12 @@ upgrading your version of coverage.py.
Unreleased
----------
-Nothing yet.
+- Fix: using the "sysmon" measurement core in 7.11.1, if Python code was
+ claimed to come from a non-Python file, a ``NotPython`` exception could be
+ raised. This could happen for example with Jinja templates compiled to
+ Python, as reported in `issue 2077`_. This is now fixed.
+
+.. _issue 2077: https://github.com/nedbat/coveragepy/issues/2077
.. start-releases
diff --git a/coverage/core.py b/coverage/core.py
index e88289ce3..6edb12432 100644
--- a/coverage/core.py
+++ b/coverage/core.py
@@ -137,3 +137,6 @@ def _debug(msg: str) -> None:
self.systrace = True
else:
raise ConfigError(f"Unknown core value: {core_name!r}")
+
+ def __repr__(self) -> str:
+ return f""
diff --git a/coverage/sysmon.py b/coverage/sysmon.py
index a46c92620..c31da2c03 100644
--- a/coverage/sysmon.py
+++ b/coverage/sysmon.py
@@ -19,6 +19,7 @@
from coverage import env
from coverage.bytecode import TBranchTrails, always_jumps, branch_trails
from coverage.debug import short_filename, short_stack
+from coverage.exceptions import NotPython
from coverage.misc import isolate_module
from coverage.parser import PythonParser
from coverage.types import (
@@ -470,5 +471,12 @@ def sysmon_branch_either(
def get_multiline_map(filename: str) -> dict[TLineNo, TLineNo]:
"""Get a PythonParser for the given filename, cached."""
parser = PythonParser(filename=filename)
- parser.parse_source()
+ try:
+ parser.parse_source()
+ except NotPython:
+ # The file was not Python. This can happen when the code object refers
+ # to an original non-Python source file, like a Jinja template.
+ # In that case, just return an empty map, which might lead to slightly
+ # wrong branch coverage, but we don't have any better option.
+ return {}
return parser.multiline_map
diff --git a/tests/test_arcs.py b/tests/test_arcs.py
index 96250d3eb..185a7f5ef 100644
--- a/tests/test_arcs.py
+++ b/tests/test_arcs.py
@@ -5,6 +5,8 @@
from __future__ import annotations
+import textwrap
+
import pytest
from tests.coveragetest import CoverageTest
@@ -2349,3 +2351,23 @@ def fun1(x):
data = cov.get_data()
fun1_lines = sorted_lines(data, abs_file("fun1.py"))
assert_count_equal(fun1_lines, [1, 2, 5])
+
+
+class NonPythonFileTest(CoverageTest):
+ """Tools like Jinja run code credited to non-Python files."""
+
+ def test_non_python_file(self) -> None:
+ # Make a code object with branches, and claim it came from an HTML file.
+ # With sysmon, this used to fail trying to parse the source. #2077
+ self.make_file("hello.html", "
Hello!
")
+ code = textwrap.dedent("""\
+ a = 1
+ while a:
+ c = 3
+ break
+ assert c == 5 - 2
+ """)
+ code_obj = compile(code, filename="hello.html", mode="exec")
+ cov = coverage.Coverage(branch=True, debug=["trace"])
+ with cov.collect():
+ exec(code_obj)
From 4a0cd9eb7aaf042f0565e90acc52b4e7f8156b77 Mon Sep 17 00:00:00 2001
From: Ned Batchelder
Date: Sat, 8 Nov 2025 14:16:13 -0500
Subject: [PATCH 2/5] docs: a fuller explanation of the core selection changes
in 7.11.1
---
CHANGES.rst | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/CHANGES.rst b/CHANGES.rst
index b4e53cdcf..daf4b9a5a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -28,6 +28,8 @@ Unreleased
raised. This could happen for example with Jinja templates compiled to
Python, as reported in `issue 2077`_. This is now fixed.
+- Doc: corrected the first entry in the 7.11.1 changelog.
+
.. _issue 2077: https://github.com/nedbat/coveragepy/issues/2077
@@ -38,11 +40,25 @@ Unreleased
Version 7.11.1 — 2025-11-07
---------------------------
+- Fix: some chanages to details of how the measurement core is chosen, and how
+ conflicting settings are handled. The "sysmon" core cannot be used with some
+ conurrency settings, with dynamic context, and in Python 3.12/3.13, with
+ branch measurement.
+
+ - If the core is not specified and defaults to "sysmon" (Python 3.14+), but
+ other settings conflict with sysmon, then the "ctrace" core will be used
+ instead with no warning. For concurrency conflicts, this used to produce an
+ error, as described in `issue 2064`_.
+
+ - If the "sysmon" core is explicitly requested in your configuration, but
+ other settings conflict, an error is now raised. This used to produce a
+ warning.
+
- Fix: if the measurement core defaults to "sysmon" (the default for Python
3.14+ since v7.9.1), but sysmon can't support some aspect of your
configuration (concurrency settings, dynamic contexts, and so on), then the
ctrace core is used instead. Previously, this would result in an error.
- Now a warning is issued instead, explaining the fallback. An explicit request
+ An explicit request
for sysmon with conflicting settings will still result in an error. Closes
`issue 2064`_.
From d0d15dcf7339d1ea7591a4d1f694ac0244b5327e Mon Sep 17 00:00:00 2001
From: Ned Batchelder
Date: Sat, 8 Nov 2025 14:29:44 -0500
Subject: [PATCH 3/5] docs: prep for 7.11.2
---
CHANGES.rst | 10 ++++++----
coverage/version.py | 4 ++--
doc/conf.py | 6 +++---
3 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/CHANGES.rst b/CHANGES.rst
index daf4b9a5a..e48aa607f 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -20,8 +20,12 @@ upgrading your version of coverage.py.
.. Version 9.8.1 — 2027-07-27
.. --------------------------
-Unreleased
-----------
+.. start-releases
+
+.. _changes_7-11-2:
+
+Version 7.11.2 — 2025-11-08
+---------------------------
- Fix: using the "sysmon" measurement core in 7.11.1, if Python code was
claimed to come from a non-Python file, a ``NotPython`` exception could be
@@ -33,8 +37,6 @@ Unreleased
.. _issue 2077: https://github.com/nedbat/coveragepy/issues/2077
-.. start-releases
-
.. _changes_7-11-1:
Version 7.11.1 — 2025-11-07
diff --git a/coverage/version.py b/coverage/version.py
index 3e59950de..fffb76e9f 100644
--- a/coverage/version.py
+++ b/coverage/version.py
@@ -8,8 +8,8 @@
# version_info: same semantics as sys.version_info.
# _dev: the .devN suffix if any.
-version_info = (7, 11, 2, "alpha", 0)
-_dev = 1
+version_info = (7, 11, 2, "final", 0)
+_dev = 0
def _make_version(
diff --git a/doc/conf.py b/doc/conf.py
index 37cf1f17a..ee0ee33c3 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -68,11 +68,11 @@
# @@@ editable
copyright = "2009–2025, Ned Batchelder" # pylint: disable=redefined-builtin
# The short X.Y.Z version.
-version = "7.11.1"
+version = "7.11.2"
# The full version, including alpha/beta/rc tags.
-release = "7.11.1"
+release = "7.11.2"
# The date of release, in "monthname day, year" format.
-release_date = "November 7, 2025"
+release_date = "November 8, 2025"
# @@@ end
rst_epilog = f"""
From e632a787b3839e4a6ecd432c665d23dd06df3a22 Mon Sep 17 00:00:00 2001
From: Ned Batchelder
Date: Sat, 8 Nov 2025 14:30:06 -0500
Subject: [PATCH 4/5] docs: sample HTML for 7.11.2
---
doc/sample_html/class_index.html | 8 ++++----
doc/sample_html/function_index.html | 8 ++++----
doc/sample_html/index.html | 8 ++++----
doc/sample_html/status.json | 2 +-
doc/sample_html/z_7b071bdc2a35fa80___init___py.html | 8 ++++----
doc/sample_html/z_7b071bdc2a35fa80___main___py.html | 8 ++++----
doc/sample_html/z_7b071bdc2a35fa80_cogapp_py.html | 8 ++++----
doc/sample_html/z_7b071bdc2a35fa80_hashhandler_py.html | 8 ++++----
doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html | 8 ++++----
doc/sample_html/z_7b071bdc2a35fa80_test_cogapp_py.html | 8 ++++----
doc/sample_html/z_7b071bdc2a35fa80_test_makefiles_py.html | 8 ++++----
.../z_7b071bdc2a35fa80_test_whiteutils_py.html | 8 ++++----
doc/sample_html/z_7b071bdc2a35fa80_utils_py.html | 8 ++++----
doc/sample_html/z_7b071bdc2a35fa80_whiteutils_py.html | 8 ++++----
14 files changed, 53 insertions(+), 53 deletions(-)
diff --git a/doc/sample_html/class_index.html b/doc/sample_html/class_index.html
index ea8dcedb7..2a82cd123 100644
--- a/doc/sample_html/class_index.html
+++ b/doc/sample_html/class_index.html
@@ -56,8 +56,8 @@