From ba87b1582e9fb0ede69474e33f74f00fa9028773 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sun, 12 Apr 2026 21:58:18 +0200 Subject: [PATCH] Fix coverage SQLite corruption: isolate each package run with COVERAGE_FILE Each package subprocess now writes to its own tmpfile via COVERAGE_FILE env. This prevents sequential subprocess runs from stomping on the .coverage SQLite DB that the prior run left behind, which caused INTERNALERROR when pytest-cov tried to combine() parallel data files with incompatible schemas. --- scripts/pytest_changed_packages.py | 42 ++++++++++++++++++------------ 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/scripts/pytest_changed_packages.py b/scripts/pytest_changed_packages.py index 3781b95..3e9456e 100755 --- a/scripts/pytest_changed_packages.py +++ b/scripts/pytest_changed_packages.py @@ -12,10 +12,12 @@ all tests are run as a fallback. from __future__ import annotations import gc +import os from pathlib import Path, PurePosixPath import shutil import subprocess import sys +import tempfile _MIN_SUBPACKAGE_DEPTH = 2 _PER_PACKAGE_MEM = "2G" @@ -95,23 +97,29 @@ def main() -> int: # instantly at the limit instead of thrashing swap/zram. use_cgroup = shutil.which("systemd-run") is not None for pkg in sorted(packages): - # Remove stale .coverage* files before each package run to prevent - # SQLite corruption when combining parallel coverage data files. - for stale in Path().glob(".coverage*"): - stale.unlink(missing_ok=True) - cmd = _build_pytest_command({pkg}) - if use_cgroup: - cmd = [ - "systemd-run", - "--user", - "--scope", - "-p", - f"MemoryMax={_PER_PACKAGE_MEM}", - "-p", - "MemorySwapMax=0", - *cmd, - ] - result = subprocess.run(cmd, check=False) + # Each package gets its own isolated coverage data file so parallel + # cgroup subprocesses never stomp on each other's SQLite DB. + with tempfile.NamedTemporaryFile( + prefix=f".coverage_{pkg}_", dir=".", delete=False + ) as tmp: + cov_file = tmp.name + try: + cmd = _build_pytest_command({pkg}) + env = {**os.environ, "COVERAGE_FILE": cov_file} + if use_cgroup: + cmd = [ + "systemd-run", + "--user", + "--scope", + "-p", + f"MemoryMax={_PER_PACKAGE_MEM}", + "-p", + "MemorySwapMax=0", + *cmd, + ] + result = subprocess.run(cmd, check=False, env=env) + finally: + Path(cov_file).unlink(missing_ok=True) gc.collect() if result.returncode != 0: return result.returncode