From 6fd92c4c9bcc56efb64a2f8743d5a2993bcfd42d Mon Sep 17 00:00:00 2001 From: "Robert C. Martin" Date: Wed, 21 Oct 2026 09:16:07 -0500 Subject: [PATCH] Fix Python coverage for top-level modules Why: for a top-level file like carddav.py, crapper passed --source=carddav.py to coverage.py, which expects a module name, so the file always scored 0%. What: python_sources now converts files to module names via _source_name. Proof: new failing test in tests/test_runners.py, then fix; suite 146/146; carddav.py now measured at 100% in family-and-friends-store. --- src/crapper/runners.py | 10 +++++++++- tests/test_runners.py | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/crapper/runners.py b/src/crapper/runners.py index 84869ee..9b02fbc 100644 --- a/src/crapper/runners.py +++ b/src/crapper/runners.py @@ -361,10 +361,18 @@ def python_sources(package: Path, files: list[Path]) -> str: relative = path.resolve().relative_to(package) except ValueError: continue - tops.add(relative.parts[0]) + tops.add(_source_name(relative)) return ",".join(sorted(tops)) +def _source_name(relative: Path) -> str: + """A top-level module is named without .py, which coverage.py --source requires.""" + + if len(relative.parts) == 1: + return relative.stem + return relative.parts[0] + + def python_coverage_commands( py: str, kind: str, data_file: Path, report: Path, source: str ) -> tuple[list[str], list[str]]: diff --git a/tests/test_runners.py b/tests/test_runners.py index 8a9f554..679e1ba 100644 --- a/tests/test_runners.py +++ b/tests/test_runners.py @@ -542,3 +542,8 @@ def test_vitest_install_restores_manifests_when_install_changes_them(tmp_path, m monkeypatch.setattr("crapper.runners.run_shell", shell) assert _ensure_vitest_coverage(tmp_path) is False assert package_json.read_bytes() == b'{"name":"demo"}\n' + + +def test_python_sources_name_a_top_level_module_without_its_suffix(tmp_path): + module = tmp_path / "carddav.py" + assert python_sources(tmp_path, [module, tmp_path / "test_carddav.py"]) == "carddav"