fix(coverage): handle nested coverage collection (#3823)

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.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f431cd9..7efdd66 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -114,6 +114,8 @@
   ([#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
diff --git a/python/private/stage2_bootstrap_template.py b/python/private/stage2_bootstrap_template.py
index c4326bc..a66b642 100644
--- a/python/private/stage2_bootstrap_template.py
+++ b/python/private/stage2_bootstrap_template.py
@@ -406,7 +406,7 @@
             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,