Skip to content

feat(toolchain): use a uv.lock based coverage hub for the bzlmod toolchains - #4415

Draft
aignas wants to merge 38 commits into
bazel-contrib:mainfrom
aignas:aignas.feat.coverage-platform-whls
Draft

aignas wants to merge 38 commits into
bazel-contrib:mainfrom
aignas:aignas.feat.coverage-platform-whls

Conversation

@aignas

@aignas aignas commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

With bzlmod, use the coverage package from a new rules_python_coverage
pip hub as the default coverage tool of the hermetic toolchains when
python.toolchain(configure_coverage_tool = True) is used.

The coverage dependency is defined in a separate pyproject.toml file and
locked in a uv.lock file, which has the latest coverage version that
supports each of the Python versions starting from 3.9. The hub is defined in
the MODULE.bazel of rules_python for each Python version with
target_platforms = ["*"], so it has the wheels for all of the platforms of
the hermetic toolchains and the coverage tool works when cross-building. The
versions that do not have a registered toolchain are ignored. Update the lock
file with bazel run //python/private/coverage:requirements.update.

The docs now recommend passing a py_library as the coverage tool of the
toolchain. Using a target that does not provide PyInfo will be deprecated in
the next version.

WORKSPACE still uses the bundled coverage wheels and will be migrated
separately.

Stacked on #4433, #4455 and #4456.

Work towards #3902

@aignas
aignas requested a review from rickeylev as a code owner November 7, 2026 05:06
@aignas

aignas commented Nov 7, 2026

Copy link
Copy Markdown
Collaborator Author

This PR was written by an AI coding agent (Claude Code) under the direction of @aignas, who is responsible for the change and reviews it before merge (semi-autonomous). The agent monitors CI and pushes fixes for CI failures; review comments are handled by the human author, who may use the agent to prepare follow-up changes.

This is an agent-generated comment, posted at the request of the PR author.

…ge tool

Before this change the coverage collection was only exercised by running
`bazel coverage` on a few targets in CI and the collected data was not
checked.

This adds a test that runs as part of `bazel test`. A `py_reconfig_test` is
built with `--collect_code_coverage` for a Python 3.12 toolchain that has the
bundled coverage tool configured, and `coverage_collection_test` runs it with
the same environment variables that `bazel coverage` sets and checks the line
coverage in the produced lcov file.

* Adds the `collect_code_coverage` attribute to `py_reconfig_*` rules.
* Configures the bundled coverage tool for the Python 3.12 dev toolchain.

Stacked on bazel-contrib#4415.

Work towards bazel-contrib#3902
Registering the toolchain with the `3.12` minor version made it take
precedence over the `3.12.16` toolchain that //tests/toolchains expects.
…ests

Run the instrumented program once and check the line and branch coverage
of particular lines in separate tests.
aignas added 15 commits November 8, 2026 12:09
Allow py_runtime.coverage_tool to be a py_library of coverage.py, such as
@pypi//coverage, by using its coverage/__main__.py file as the entry
point. This allows users to use the coverage version that is locked in
their requirements.
A py_library depends on the Python toolchain, so using @pypi//coverage
as the coverage_tool of the toolchain creates a dependency cycle. Instead
find the coverage/__main__.py entry point in the files of the target, so
that @pypi//coverage:extracted_whl_files can be used.
It is used to test the coverage collection with the coverage tool from a
PyPI hub.
…p hub

Configure a 3.13 toolchain with the extracted coverage wheel from the
dev_pip hub as the coverage tool and run the same coverage collection
checks as for the bundled coverage tool.
Use TEST_TMPDIR directly and rely on the test working directory being the
workspace runfiles directory.
Also drop the lib.py data dependency, which is already in the runfiles via
the instrumented target.
Also test the error for a coverage_tool without coverage/__main__.py and
name the news entry after the PR.
@aignas
aignas force-pushed the aignas.feat.coverage-platform-whls branch from 311bac6 to a28e478 Compare November 9, 2026 10:20
@aignas
aignas marked this pull request as ready for review November 9, 2026 10:20
…e tool

Using a `py_library`, such as `@pypi//coverage`, as the `coverage_tool`
created a dependency cycle: the `py_library` resolves the Python toolchain,
whose `py_runtime` depends on the `coverage_tool` again.

Similarly to how `rules_go` builds `nogo`, the `coverage_tool` attribute
now transitions to a configuration where a private bootstrap flag is set
and `collect_code_coverage` is disabled. The `py_runtime` macro drops the
`coverage_tool` dependency in that configuration, so the cycle is broken.
The hermetic toolchains already select on `collect_code_coverage`.
The bootstrap never executes the coverage tool file: it only adds the
grandparent directory of it to `sys.path` and imports `coverage`. Instead
of searching for `coverage/__main__.py` within the files of the target,
use the import paths of a `coverage_tool` that provides `PyInfo`, e.g.
`@pypi//coverage`.

* Adds `PyRuntimeInfo.coverage_imports`, which is mutually exclusive with
  `PyRuntimeInfo.coverage_tool`.
* Adds the `%coverage_imports%` substitution to the site init template.
@aignas

aignas commented Nov 9, 2026

Copy link
Copy Markdown
Collaborator Author

With #4433 this is no longer needed, I think we can just transition to using a particular hub instead. This will also make sure that we are targeting supported values by default.

@aignas
aignas marked this pull request as draft November 9, 2026 10:34
aignas added 10 commits November 9, 2026 19:57
Allow selecting all of the platforms configured with `pip.default` without
listing them one by one. This is useful for hubs that need to support
cross-building for any of the configured platforms, e.g. a hub that provides
a tool for every toolchain.
…rage tool

Define the `coverage` dependency in a separate `pyproject.toml` with a
`uv.lock` file, which locks the latest `coverage` version for each Python
version starting from 3.9. The lock file is used by the new
`rules_python_coverage` pip hub, which has the wheels for all of the platforms
configured with `pip.default`.

With bzlmod, `python.toolchain(configure_coverage_tool = True)` now uses
`@rules_python_coverage//coverage` as the coverage tool. WORKSPACE still uses
the bundled coverage wheels.
Document the `rules_python_coverage` hub and recommend passing a `py_library`
as the coverage tool. Using a target without `PyInfo` will be deprecated in
the next version.
…s = ["*"]

When `target_platforms = ["*"]` is used with a `uv.lock` file, add the
platform independent wheel of a package, if there is one, as a fallback for
the Python version. The platforms that are not configured with `pip.default`
can then still use the package, whilst the configured platforms keep using
the more specific wheels.
The default `pip.default` platforms only covered the `x86_64` and `aarch64`
Linux, macOS and Windows platforms, so the toolchains for the other platforms
could not use the wheels from a pip hub. Add the default platforms for all of
the platforms that the hermetic Python toolchains support and a test that
ensures that each toolchain platform variant has a matching pip platform.

The glibc Linux platforms now also match on `--py_linux_libc`, so that they
do not overlap with the new musl platform, which uses the `musllinux` wheels.
@aignas
aignas force-pushed the aignas.feat.coverage-platform-whls branch from a28e478 to b36ae25 Compare November 9, 2026 11:24
@aignas aignas changed the title feat(toolchain): use the platform specific coverage wheels on more platforms feat(toolchain): use a uv.lock based coverage hub for the bzlmod toolchains Nov 9, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant