fix(bzlmod): convert coverage_tool Label to string (#4157)
The `coverage_tool` attribute on
`python.single_version_platform_override` is declared as a Label, but
the value was passed through unchanged to `python_repository`, which
declares `coverage_tool` as a string. This caused a type mismatch error
at module-extension evaluation time whenever `coverage_tool` was set.
Convert the Label to its canonical string form before storing it. Fixes
#2570.
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
diff --git a/news/2570.fixed.md b/news/2570.fixed.md
new file mode 100644
index 0000000..f31115d
--- /dev/null
+++ b/news/2570.fixed.md
@@ -0,0 +1,3 @@
+(bzlmod) Fixed a type mismatch error when using {obj}`coverage_tool` with
+{obj}`python.single_version_platform_override`
+([#2570](https://github.com/bazel-contrib/rules_python/issues/2570)).
diff --git a/python/private/python.bzl b/python/private/python.bzl
index 70a3bd9..9fed939 100644
--- a/python/private/python.bzl
+++ b/python/private/python.bzl
@@ -626,7 +626,10 @@
available_versions[tag.python_version] = {}
if tag.coverage_tool:
- available_versions[tag.python_version].setdefault("coverage_tool", {})[tag.platform] = tag.coverage_tool
+ # NOTE: tag.coverage_tool is a Label (so that it is resolved relative to the
+ # calling module), but downstream (python_repository.coverage_tool) it is
+ # consumed as a string, so convert it to its canonical string form here.
+ available_versions[tag.python_version].setdefault("coverage_tool", {})[tag.platform] = str(tag.coverage_tool)
if tag.patch_strip:
available_versions[tag.python_version].setdefault("patch_strip", {})[tag.platform] = tag.patch_strip
if tag.patches:
diff --git a/tests/python/python_tests.bzl b/tests/python/python_tests.bzl
index 5636b7e..ef7ccf0 100644
--- a/tests/python/python_tests.bzl
+++ b/tests/python/python_tests.bzl
@@ -481,7 +481,11 @@
],
single_version_platform_override = [
python_ext.single_version_platform_override(
- coverage_tool = "specific_cov_tool",
+ # `coverage_tool` is declared as `attr.label` on the tag class
+ # (so bzlmod resolves it relative to the calling module), so it
+ # is a `Label`, not a plain `str`, by the time it reaches here.
+ # See https://github.com/bazel-contrib/rules_python/issues/2570.
+ coverage_tool = Label("@my_module//:specific_cov_tool"),
patch_strip = 2,
patches = ["specific-patch.txt"],
platform = "aarch64-unknown-linux-gnu",
@@ -509,8 +513,15 @@
"strip_prefix": {"aarch64-unknown-linux-gnu": "prefix"},
"url": {"aarch64-unknown-linux-gnu": ["example.org"]},
})
+
+ # The Label must be converted to its canonical string form: `python_repository`
+ # (which ultimately consumes this value) declares `coverage_tool` as `attr.string`.
+ coverage_tool = py.config.default["tool_versions"]["3.13.99"]["coverage_tool"]["aarch64-unknown-linux-gnu"]
+ env.expect.that_str(type(coverage_tool)).equals("string")
+ env.expect.that_str(coverage_tool).equals(str(Label("@my_module//:specific_cov_tool")))
+
env.expect.that_dict(py.config.default["tool_versions"]["3.13.99"]).contains_exactly({
- "coverage_tool": {"aarch64-unknown-linux-gnu": "specific_cov_tool"},
+ "coverage_tool": {"aarch64-unknown-linux-gnu": coverage_tool},
"patch_strip": {"aarch64-unknown-linux-gnu": 2},
"patches": {"aarch64-unknown-linux-gnu": ["specific-patch.txt"]},
"sha256": {"aarch64-unknown-linux-gnu": "deadb00f"},