#!/usr/bin/env python3 """Run the optional CI coverage baseline lane.""" from __future__ import annotations import argparse import importlib.util import os import subprocess import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[1] def required_coverage_dependency_modules() -> tuple[tuple[str, str], ...]: """Return import modules required before pytest can collect coverage tests.""" return ( ("pytest", "pytest"), ("pytest_cov", "pytest-cov"), ("aiohttp", "aiohttp"), ("anyio", "anyio"), ("numpy", "numpy"), ("PIL", "pillow"), ) def build_coverage_command( python_exe: str, *, xml_path: str = "coverage.xml", fail_under: int = 0, ) -> list[str]: command = [ python_exe, "-m", "pytest", "tests", "--cov=.", "--cov-report=term-missing:skip-covered", f"--cov-fail-under={fail_under}", ] if xml_path: command.append(f"--cov-report=xml:{xml_path}") return command def require_coverage_dependencies() -> None: missing = [ package_name for module_name, package_name in required_coverage_dependency_modules() if importlib.util.find_spec(module_name) is None ] if missing: packages = ", ".join(missing) raise RuntimeError( f"Missing coverage/test dependency: {packages}. " "Install dev dependencies with: python -m pip install -r requirements-dev.txt" ) def _require_pytest_cov() -> None: require_coverage_dependencies() def parse_args(argv: list[str]) -> argparse.Namespace: parser = argparse.ArgumentParser(description="Run pytest with coverage baseline reporting.") parser.add_argument( "--xml", default="coverage.xml", help="Coverage XML output path. Use an empty value to skip XML output.", ) parser.add_argument( "--fail-under", type=int, default=0, help="Coverage threshold. Defaults to 0 for baseline reporting only.", ) return parser.parse_args(argv) def main(argv: list[str] | None = None) -> int: args = parse_args(argv or sys.argv[1:]) try: require_coverage_dependencies() except RuntimeError as exc: print(str(exc), file=sys.stderr) return 2 env = os.environ.copy() env.setdefault("DOCTOR_STATE_DIR", str(PROJECT_ROOT / "doctor_state" / "_coverage")) command = build_coverage_command( sys.executable, xml_path=args.xml, fail_under=args.fail_under, ) return subprocess.call(command, cwd=PROJECT_ROOT, env=env) if __name__ == "__main__": raise SystemExit(main())