From 0a49dcfb096147e0346db517b733cfda915fc722 Mon Sep 17 00:00:00 2001 From: Pierre Gergondet Date: Tue, 16 Jun 2026 18:50:48 +0900 Subject: [PATCH 1/2] fix(coverage): handle nested coverage collection We discovered that when a py_test invokes py_binary, coverage information collected by those binaries is lost and only the coverage of the test itself appears. It turns out that each binary writes to the same coverage file and only the last one is included in the report. This PR makes the lcov_path unique, ensuring the coverage is collected for every binary that might be launched in such a setup. I have setup https://github.com/gergondet-woven/repro-rules_python-coverage-issue to show the issue. In this repo, a py_binary is launched through a py_test and we would expect coverage information generated by the binary to surface in the coverage report but it doesn't with the current release: Before the patch: ``` # Generate coverage information bazel coverage --combined_report=lcov //... # Generate the report genhtml --ignore-errors category --branch-coverage --output ~/genhtml "$(bazel info output_path)/_coverage/_coverage_report.dat" # (snip) Overall coverage rate: lines......: 30.0% (3 of 10 lines) # Looking into the report, neither coverage for the library function # called by the binary nor the binary code itself is collected ``` After applying the patch: ``` Overall coverage rate: lines......: 100.0% (11 of 11 lines) ``` However, I am not sure how/if this can be properly tested within rules_python itself. --- python/private/stage2_bootstrap_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/private/stage2_bootstrap_template.py b/python/private/stage2_bootstrap_template.py index c4326bc026..a66b6428b0 100644 --- a/python/private/stage2_bootstrap_template.py +++ b/python/private/stage2_bootstrap_template.py @@ -406,7 +406,7 @@ def _maybe_collect_coverage(enable): yield finally: cov.stop() - lcov_path = os.path.join(coverage_dir, "pylcov.dat") + lcov_path = os.path.join(coverage_dir, "pylcov_{}.dat".format(unique_id)) print_verbose_coverage("generating lcov from:", lcov_path) cov.lcov_report( outfile=lcov_path, From 7182c1c4bdb58b48a0c25c6cfcee34b8623f00c9 Mon Sep 17 00:00:00 2001 From: Pierre Gergondet Date: Tue, 16 Jun 2026 19:06:26 +0900 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f431cd995e..7efdd66312 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,6 +114,8 @@ END_UNRELEASED_TEMPLATE ([#1975](https://github.com/bazel-contrib/rules_python/issues/1975)) * (uv) automatically pass the `--project` parameter based on the source files. ([#3087](https://github.com/bazel-contrib/rules_python/issues/3087)) +* (coverage) handle nested coverage collection + ([#3823](https://github.com/bazel-contrib/rules_python/pull/3823)) {#v0-0-0-added} ### Added