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 @@

Classes

- 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 @@

- 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