diff --git a/.github/workflows/kit.yml b/.github/workflows/kit.yml
index 10015fbf2..816378285 100644
--- a/.github/workflows/kit.yml
+++ b/.github/workflows/kit.yml
@@ -36,7 +36,7 @@ env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
# PYVERSIONS: changing the list of versions will change the number of
# expected distributions. This must match the same number in publish.yml.
- EXPECTED: 92
+ EXPECTED: 106
permissions:
contents: read
@@ -73,7 +73,7 @@ jobs:
#
# # For each OS, what arch to use with cibuildwheel:
# os_archs = {
- # "ubuntu": ["x86_64", "i686", "aarch64", "riscv64"],
+ # "ubuntu": ["x86_64", "i686", "aarch64", "riscv64", "ppc64le"],
# "macos": ["arm64", "x86_64"],
# "windows": ["x86", "AMD64", "ARM64"],
# }
@@ -111,6 +111,8 @@ jobs:
# if the_arch == "aarch64":
# # https://github.com/pypa/cibuildwheel/issues/2257
# them["os-version"] = "22.04-arm"
+ # if the_arch == "ppc64le":
+ # them["os-version"] = "24.04-ppc64le"
# print(f"- {json.dumps(them)}")
# ]]]
- {"os": "ubuntu", "py": "cp310", "arch": "x86_64", "cipy": "3.11"}
@@ -133,6 +135,11 @@ jobs:
- {"os": "ubuntu", "py": "cp312", "arch": "riscv64", "cipy": "3.11"}
- {"os": "ubuntu", "py": "cp313", "arch": "riscv64", "cipy": "3.11"}
- {"os": "ubuntu", "py": "cp314", "arch": "riscv64", "cipy": "3.11"}
+ - {"os": "ubuntu", "py": "cp310", "arch": "ppc64le", "cipy": "3.11", "os-version": "24.04-ppc64le"}
+ - {"os": "ubuntu", "py": "cp311", "arch": "ppc64le", "cipy": "3.11", "os-version": "24.04-ppc64le"}
+ - {"os": "ubuntu", "py": "cp312", "arch": "ppc64le", "cipy": "3.11", "os-version": "24.04-ppc64le"}
+ - {"os": "ubuntu", "py": "cp313", "arch": "ppc64le", "cipy": "3.11", "os-version": "24.04-ppc64le"}
+ - {"os": "ubuntu", "py": "cp314", "arch": "ppc64le", "cipy": "3.11", "os-version": "24.04-ppc64le"}
- {"os": "macos", "py": "cp310", "arch": "arm64", "cipy": "3.11", "os-version": "14"}
- {"os": "macos", "py": "cp311", "arch": "arm64", "cipy": "3.11", "os-version": "14"}
- {"os": "macos", "py": "cp312", "arch": "arm64", "cipy": "3.11", "os-version": "14"}
@@ -157,7 +164,7 @@ jobs:
- {"os": "windows", "py": "cp312", "arch": "ARM64", "cipy": "3.11", "os-version": "11-arm"}
- {"os": "windows", "py": "cp313", "arch": "ARM64", "cipy": "3.11", "os-version": "11-arm"}
- {"os": "windows", "py": "cp314", "arch": "ARM64", "cipy": "3.11", "os-version": "11-arm"}
- # [[[end]]] (sum: UDdYTxMoTi)
+ # [[[end]]] (sum: AhCqn9SafY)
# ^^^^^^^^^^^^^^^
# If a check fails and points to this checksum line, it means you edited
# the matrix directly instead of editing the Python code in the comment
@@ -172,7 +179,8 @@ jobs:
with:
persist-credentials: false
- - name: "Install Python"
+ - if: ${{ matrix.arch != 'ppc64le' }}
+ name: "Install Python"
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "${{ matrix.cipy }}"
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 3f6817651..997bc1540 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -17,7 +17,7 @@ defaults:
env:
# PYVERSIONS: changing the list of versions will change the number of
# expected distributions. This must match the same number in kit.yml.
- EXPECTED: 92
+ EXPECTED: 106
permissions:
contents: read
@@ -81,7 +81,7 @@ jobs:
files=$(ls dist 2>/dev/null | wc -l) && [ "$files" -eq $EXPECTED ] || exit 1
- name: "Generate attestations"
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3.1.0
+ uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0
with:
subject-path: "dist/*"
@@ -121,7 +121,7 @@ jobs:
files=$(ls dist 2>/dev/null | wc -l) && [ "$files" -eq $EXPECTED ] || exit 1
- name: "Generate attestations"
- uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8 # v3.1.0
+ uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0
with:
subject-path: "dist/*"
diff --git a/CHANGES.rst b/CHANGES.rst
index 4905d94fb..d9b4d40d7 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -22,6 +22,27 @@ upgrading your version of coverage.py.
.. start-releases
+.. _changes_7-13-4:
+
+Version 7.13.4 — 2026-02-09
+---------------------------
+
+- Fix: the third-party code fix in 7.13.3 required examining the parent
+ directories where coverage was run. In the unusual situation that one of the
+ parent directories is unreadable, a PermissionError would occur, as
+ described in `issue 2129`_. This is now fixed.
+
+- Fix: in test suites that change sys.path, coverage.py could fail with
+ "RuntimeError: Set changed size during iteration" as described and fixed in
+ `pull 2130`_. Thanks, Noah Fatsi.
+
+- We now publish ppc64le wheels, thanks to `Pankhudi Jain `_.
+
+.. _pull 2121: https://github.com/coveragepy/coveragepy/pull/2121
+.. _issue 2129: https://github.com/coveragepy/coveragepy/issues/2129
+.. _pull 2130: https://github.com/coveragepy/coveragepy/pull/2130
+
+
.. _changes_7-13-3:
Version 7.13.3 — 2026-02-03
@@ -92,6 +113,7 @@ Version 7.13.1 — 2025-12-28
.. _issue 2109: https://github.com/coveragepy/coveragepy/issues/2109
.. _issue 2110: https://github.com/coveragepy/coveragepy/issues/2110
+
.. _changes_7-13-0:
Version 7.13.0 — 2025-12-08
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 3e56e7e47..4bbe7e339 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -94,6 +94,7 @@ Geoff Bache
George Paci
George Song
George-Cristian Bîrzan
+Greg Biles
Greg Rogers
Guido van Rossum
Guillaume Chazarain
@@ -114,6 +115,7 @@ James Valleroy
Jan Kühle
Jan Rusak
Janakarajan Natarajan
+Janine vN
Jeremy Fleischman
Jerin Peter George
Jessamyn Smith
@@ -187,6 +189,7 @@ Nick Drozd
Nikita Bloshchanevich
Nikita Sobolev
Nils Kattenbeck
+Noah Fatsi
Noel O'Boyle
Oleg Höfling
Oleh Krehel
@@ -195,6 +198,7 @@ Olivier Grisel
Ori Avtalion
Pablo Carballo
Pankaj Pandey
+Pankhudi Jain
Patrick Mezard
Paul Timmins
Pavel Tsialnou
diff --git a/Makefile b/Makefile
index dc8c482ac..dba6636dd 100644
--- a/Makefile
+++ b/Makefile
@@ -314,11 +314,13 @@ WEBSAMPLEBETA = $(WEBHOME)/files/sample_coverage_html_beta
publish: #- Publish the sample HTML report.
rm -f $(WEBSAMPLE)/*.*
mkdir -p $(WEBSAMPLE)
+ rm doc/sample_html/status.json
cp doc/sample_html/*.* $(WEBSAMPLE)
publishbeta:
rm -f $(WEBSAMPLEBETA)/*.*
mkdir -p $(WEBSAMPLEBETA)
+ rm doc/sample_html_beta/status.json
cp doc/sample_html_beta/*.* $(WEBSAMPLEBETA)
CHANGES_MD = tmp/rst_rst/changes.md
diff --git a/coverage/files.py b/coverage/files.py
index 577d160ed..c6c17376e 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -260,10 +260,11 @@ def __init__(
caption: str = "",
debug: DebugFn = None,
) -> None:
- self.original_paths = human_sorted(paths)
+ paths_list = list(paths)
+ self.original_paths = human_sorted(paths_list)
super().__init__(self.original_paths, name=name, caption=caption, debug=debug)
self.paths = []
- for p in paths:
+ for p in paths_list:
ap = abs_file(p)
if ap != p and debug:
debug(f" Normalized {p!r} to {ap!r}")
diff --git a/coverage/inorout.py b/coverage/inorout.py
index 33f5f1ff2..aa4542f03 100644
--- a/coverage/inorout.py
+++ b/coverage/inorout.py
@@ -171,17 +171,16 @@ class DirectoryDetail:
def _analyze_directory(d: str) -> DirectoryDetail:
"""Analyze the directory `d` for existence and venv status."""
- detail = DirectoryDetail(exists=True, venv=None)
- while True:
- if not os.path.exists(d):
- detail.exists = False
- break
- d = os.path.dirname(d)
- if d == os.path.dirname(d):
- break
- if "pyvenv.cfg" in os.listdir(d):
- detail.venv = d
- break
+ detail = DirectoryDetail(exists=os.path.exists(d), venv=None)
+ if detail.exists:
+ while True:
+ d = os.path.dirname(d)
+ if d == os.path.dirname(d):
+ break
+ pyvenv = os.path.join(d, "pyvenv.cfg")
+ if os.path.exists(pyvenv):
+ detail.venv = d
+ break
return detail
@@ -189,11 +188,11 @@ def _dir_detail(d: str) -> str:
"""Get a string describing the directory `d` for debugging."""
detail = _analyze_directory(d)
if not detail.exists:
- describe = "no such dir"
+ describe = "does not exist"
elif detail.venv is not None:
describe = f"venv at {detail.venv}"
else:
- describe = "not venv"
+ describe = "not a venv"
return f"{d!r} ({describe})"
diff --git a/coverage/version.py b/coverage/version.py
index b05f693e4..8fb314f42 100644
--- a/coverage/version.py
+++ b/coverage/version.py
@@ -8,7 +8,7 @@
# version_info: same semantics as sys.version_info.
# _dev: the .devN suffix if any.
-version_info = (7, 13, 3, "final", 0)
+version_info = (7, 13, 4, "final", 0)
_dev = 0
diff --git a/doc/conf.py b/doc/conf.py
index 50a04f9c9..ac7c56227 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -68,11 +68,11 @@
# @@@ editable
copyright = "2009–2026, Ned Batchelder" # pylint: disable=redefined-builtin
# The short X.Y.Z version.
-version = "7.13.3"
+version = "7.13.4"
# The full version, including alpha/beta/rc tags.
-release = "7.13.3"
+release = "7.13.4"
# The date of release, in "monthname day, year" format.
-release_date = "February 3, 2026"
+release_date = "February 9, 2026"
# @@@ end
rst_epilog = f"""
diff --git a/doc/sample_html/class_index.html b/doc/sample_html/class_index.html
index ebfecc8cf..8d876be2a 100644
--- a/doc/sample_html/class_index.html
+++ b/doc/sample_html/class_index.html
@@ -56,8 +56,8 @@
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -882,8 +882,8 @@
@@ -97,8 +97,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80___main___py.html b/doc/sample_html/z_7b071bdc2a35fa80___main___py.html
index 21ec149ca..cce17223c 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80___main___py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80___main___py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -97,8 +97,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_cogapp_py.html b/doc/sample_html/z_7b071bdc2a35fa80_cogapp_py.html
index 97dc5f1a2..3b1f6ef20 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_cogapp_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_cogapp_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -728,8 +728,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_errors_py.html b/doc/sample_html/z_7b071bdc2a35fa80_errors_py.html
index 006defce6..9c8fc670d 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_errors_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_errors_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -130,8 +130,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_hashhandler_py.html b/doc/sample_html/z_7b071bdc2a35fa80_hashhandler_py.html
index 249fe8860..864c302b7 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_hashhandler_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_hashhandler_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -265,8 +265,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html b/doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html
index 2b2c6c229..4966688c1 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_makefiles_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -127,8 +127,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_options_py.html b/doc/sample_html/z_7b071bdc2a35fa80_options_py.html
index 24df58dc0..c404fdd43 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_options_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_options_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -383,8 +383,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_test_cogapp_py.html b/doc/sample_html/z_7b071bdc2a35fa80_test_cogapp_py.html
index b7806e4bc..e4f94c839 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_test_cogapp_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_test_cogapp_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -2950,8 +2950,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_test_makefiles_py.html b/doc/sample_html/z_7b071bdc2a35fa80_test_makefiles_py.html
index 656446f18..8cff9d6d0 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_test_makefiles_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_test_makefiles_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -205,8 +205,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_test_whiteutils_py.html b/doc/sample_html/z_7b071bdc2a35fa80_test_whiteutils_py.html
index 6acb5870d..7c249a53a 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_test_whiteutils_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_test_whiteutils_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -186,8 +186,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_utils_py.html b/doc/sample_html/z_7b071bdc2a35fa80_utils_py.html
index 6dc4c509b..08c7cff6a 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_utils_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_utils_py.html
@@ -66,8 +66,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
@@ -155,8 +155,8 @@
^ index
» next
- coverage.py v7.13.3,
- created at 2026-02-03 08:19 -0500
+ coverage.py v7.13.4,
+ created at 2026-02-09 06:46 -0500
diff --git a/doc/sample_html/z_7b071bdc2a35fa80_whiteutils_py.html b/doc/sample_html/z_7b071bdc2a35fa80_whiteutils_py.html
index dcc941a07..d6d1753cf 100644
--- a/doc/sample_html/z_7b071bdc2a35fa80_whiteutils_py.html
+++ b/doc/sample_html/z_7b071bdc2a35fa80_whiteutils_py.html
@@ -66,8 +66,8 @@