feat(pypi): pip.defaults API for customizing repo selection 2/n (#2988)
WIP: stacked on #2987
This is adding `constraint_values` attribute to `pip.configure` and is
threading it all the way down to the generation of `BUILD.bazel` file of
for
config settings used in the hub repository.
Out of scope:
- Passing `flag_values` or target settings. I am torn about it - doing
it in
this PR would flesh out the design more, but at the same time it might
become
harder to review.
- `whl_target_platforms` and `select_whls` is still unchanged, not sure
if it
is related to this attribute addition.
Work towards #2747
Work towards #2548
Work towards #260
---------
Co-authored-by: Richard Levasseur <richardlev@gmail.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9897dc9..da3dcc8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -64,7 +64,7 @@
### Added
* (pypi) To configure the environment for `requirements.txt` evaluation, use the newly added
developer preview of the `pip.default` tag class. Only `rules_python` and root modules can use
- this feature.
+ this feature. You can also configure `constraint_values` using `pip.default`.
{#v0-0-0-removed}
### Removed
diff --git a/python/private/pypi/config_settings.bzl b/python/private/pypi/config_settings.bzl
index 3e828e5..7edc578 100644
--- a/python/private/pypi/config_settings.bzl
+++ b/python/private/pypi/config_settings.bzl
@@ -111,8 +111,8 @@
glibc_versions = [],
muslc_versions = [],
osx_versions = [],
- target_platforms = [],
name = None,
+ platform_constraint_values = {},
**kwargs):
"""Generate all of the pip config settings.
@@ -126,8 +126,10 @@
configure config settings for.
osx_versions (list[str]): The list of OSX OS versions to configure
config settings for.
- target_platforms (list[str]): The list of "{os}_{cpu}" for deriving
- constraint values for each condition.
+ platform_constraint_values: {type}`dict[str, list[str]]` the constraint
+ values to use instead of the default ones. Key are platform names
+ (a human-friendly platform string). Values are lists of
+ `constraint_value` label strings.
**kwargs: Other args passed to the underlying implementations, such as
{obj}`native`.
"""
@@ -135,22 +137,17 @@
glibc_versions = [""] + glibc_versions
muslc_versions = [""] + muslc_versions
osx_versions = [""] + osx_versions
- target_platforms = [("", ""), ("osx", "universal2")] + [
- t.split("_", 1)
- for t in target_platforms
- ]
+ target_platforms = {
+ "": [],
+ # TODO @aignas 2025-06-15: allowing universal2 and platform specific wheels in one
+ # closure is making things maybe a little bit too complicated.
+ "osx_universal2": ["@platforms//os:osx"],
+ } | platform_constraint_values
for python_version in python_versions:
- for os, cpu in target_platforms:
- constraint_values = []
- suffix = ""
- if os:
- constraint_values.append("@platforms//os:" + os)
- suffix += "_" + os
- if cpu:
- suffix += "_" + cpu
- if cpu != "universal2":
- constraint_values.append("@platforms//cpu:" + cpu)
+ for platform_name, constraint_values in target_platforms.items():
+ suffix = "_{}".format(platform_name) if platform_name else ""
+ os, _, cpu = platform_name.partition("_")
_dist_config_settings(
suffix = suffix,
diff --git a/python/private/pypi/extension.bzl b/python/private/pypi/extension.bzl
index 97b6825..78511b4 100644
--- a/python/private/pypi/extension.bzl
+++ b/python/private/pypi/extension.bzl
@@ -372,7 +372,7 @@
),
)
-def _configure(config, *, platform, os_name, arch_name, override = False, env = {}):
+def _configure(config, *, platform, os_name, arch_name, constraint_values, env = {}, override = False):
"""Set the value in the config if the value is provided"""
config.setdefault("platforms", {})
if platform:
@@ -387,6 +387,7 @@
name = platform.replace("-", "_").lower(),
os_name = os_name,
arch_name = arch_name,
+ constraint_values = constraint_values,
env = env,
)
else:
@@ -413,6 +414,10 @@
arch_name = cpu,
os_name = "linux",
platform = "linux_{}".format(cpu),
+ constraint_values = [
+ "@platforms//os:linux",
+ "@platforms//cpu:{}".format(cpu),
+ ],
env = {"platform_version": "0"},
)
for cpu in [
@@ -424,17 +429,25 @@
arch_name = cpu,
# We choose the oldest non-EOL version at the time when we release `rules_python`.
# See https://endoflife.date/macos
- env = {"platform_version": "14.0"},
os_name = "osx",
platform = "osx_{}".format(cpu),
+ constraint_values = [
+ "@platforms//os:osx",
+ "@platforms//cpu:{}".format(cpu),
+ ],
+ env = {"platform_version": "14.0"},
)
_configure(
defaults,
arch_name = "x86_64",
- env = {"platform_version": "0"},
os_name = "windows",
platform = "windows_x86_64",
+ constraint_values = [
+ "@platforms//os:windows",
+ "@platforms//cpu:x86_64",
+ ],
+ env = {"platform_version": "0"},
)
return struct(**defaults)
@@ -500,6 +513,7 @@
_configure(
defaults,
arch_name = tag.arch_name,
+ constraint_values = tag.constraint_values,
env = tag.env,
os_name = tag.os_name,
platform = tag.platform,
@@ -679,6 +693,13 @@
}
for hub_name, extra_whl_aliases in extra_aliases.items()
},
+ platform_constraint_values = {
+ hub_name: {
+ platform_name: sorted([str(Label(cv)) for cv in p.constraint_values])
+ for platform_name, p in config.platforms.items()
+ }
+ for hub_name in hub_whl_map
+ },
whl_libraries = {
k: dict(sorted(args.items()))
for k, args in sorted(whl_libraries.items())
@@ -769,6 +790,7 @@
for key, values in whl_map.items()
},
packages = mods.exposed_packages.get(hub_name, []),
+ platform_constraint_values = mods.platform_constraint_values.get(hub_name, {}),
groups = mods.hub_group_map.get(hub_name),
)
@@ -790,6 +812,12 @@
:::
""",
),
+ "constraint_values": attr.label_list(
+ mandatory = True,
+ doc = """\
+The constraint_values to use in select statements.
+""",
+ ),
"os_name": attr.string(
doc = """\
The OS name to be used.
diff --git a/python/private/pypi/hub_repository.bzl b/python/private/pypi/hub_repository.bzl
index 0dbc6c2..4398d7b 100644
--- a/python/private/pypi/hub_repository.bzl
+++ b/python/private/pypi/hub_repository.bzl
@@ -34,6 +34,7 @@
},
extra_hub_aliases = rctx.attr.extra_hub_aliases,
requirement_cycles = rctx.attr.groups,
+ platform_constraint_values = rctx.attr.platform_constraint_values,
)
for path, contents in aliases.items():
rctx.file(path, contents)
@@ -83,6 +84,10 @@
The list of packages that will be exposed via all_*requirements macros. Defaults to whl_map keys.
""",
),
+ "platform_constraint_values": attr.string_list_dict(
+ doc = "The constraint values for each platform name. The values are string canonical string Label representations",
+ mandatory = False,
+ ),
"repo_name": attr.string(
mandatory = True,
doc = "The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name.",
diff --git a/python/private/pypi/render_pkg_aliases.bzl b/python/private/pypi/render_pkg_aliases.bzl
index 28f32ed..267d7ce 100644
--- a/python/private/pypi/render_pkg_aliases.bzl
+++ b/python/private/pypi/render_pkg_aliases.bzl
@@ -155,12 +155,14 @@
# Use a dict as a simple set
return sorted({_major_minor(v): None for v in python_versions})
-def render_multiplatform_pkg_aliases(*, aliases, **kwargs):
+def render_multiplatform_pkg_aliases(*, aliases, platform_constraint_values = {}, **kwargs):
"""Render the multi-platform pkg aliases.
Args:
aliases: dict[str, list(whl_config_setting)] A list of aliases that will be
transformed from ones having `filename` to ones having `config_setting`.
+ platform_constraint_values: {type}`dict[str, list[str]]` contains all of the
+ target platforms and their appropriate `constraint_values`.
**kwargs: extra arguments passed to render_pkg_aliases.
Returns:
@@ -187,18 +189,22 @@
muslc_versions = flag_versions.get("muslc_versions", []),
osx_versions = flag_versions.get("osx_versions", []),
python_versions = _major_minor_versions(flag_versions.get("python_versions", [])),
- target_platforms = flag_versions.get("target_platforms", []),
+ platform_constraint_values = platform_constraint_values,
visibility = ["//:__subpackages__"],
)
return contents
-def _render_config_settings(**kwargs):
+def _render_config_settings(platform_constraint_values, **kwargs):
return """\
load("@rules_python//python/private/pypi:config_settings.bzl", "config_settings")
{}""".format(render.call(
"config_settings",
name = repr("config_settings"),
+ platform_constraint_values = render.dict(
+ platform_constraint_values,
+ value_repr = render.list,
+ ),
**_repr_dict(value_repr = render.list, **kwargs)
))
diff --git a/tests/pypi/config_settings/config_settings_tests.bzl b/tests/pypi/config_settings/config_settings_tests.bzl
index f111d0c..9551d42 100644
--- a/tests/pypi/config_settings/config_settings_tests.bzl
+++ b/tests/pypi/config_settings/config_settings_tests.bzl
@@ -657,13 +657,34 @@
glibc_versions = [(2, 14), (2, 17)],
muslc_versions = [(1, 1)],
osx_versions = [(10, 9), (11, 0)],
- target_platforms = [
- "windows_x86_64",
- "windows_aarch64",
- "linux_x86_64",
- "linux_ppc",
- "linux_aarch64",
- "osx_x86_64",
- "osx_aarch64",
- ],
+ platform_constraint_values = {
+ "linux_aarch64": [
+ "@platforms//cpu:aarch64",
+ "@platforms//os:linux",
+ ],
+ "linux_ppc": [
+ "@platforms//cpu:ppc",
+ "@platforms//os:linux",
+ ],
+ "linux_x86_64": [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:linux",
+ ],
+ "osx_aarch64": [
+ "@platforms//cpu:aarch64",
+ "@platforms//os:osx",
+ ],
+ "osx_x86_64": [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:osx",
+ ],
+ "windows_aarch64": [
+ "@platforms//cpu:aarch64",
+ "@platforms//os:windows",
+ ],
+ "windows_x86_64": [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:windows",
+ ],
+ },
)
diff --git a/tests/pypi/extension/extension_tests.bzl b/tests/pypi/extension/extension_tests.bzl
index 3d205a2..231e8ca 100644
--- a/tests/pypi/extension/extension_tests.bzl
+++ b/tests/pypi/extension/extension_tests.bzl
@@ -1051,6 +1051,10 @@
default = [
_default(
platform = "{}_{}".format(os, cpu),
+ constraint_values = [
+ "@platforms//os:{}".format(os),
+ "@platforms//cpu:{}".format(cpu),
+ ],
)
for os, cpu in [
("linux", "x86_64"),
diff --git a/tests/pypi/pkg_aliases/pkg_aliases_test.bzl b/tests/pypi/pkg_aliases/pkg_aliases_test.bzl
index 71ca811..0fbcd4e 100644
--- a/tests/pypi/pkg_aliases/pkg_aliases_test.bzl
+++ b/tests/pypi/pkg_aliases/pkg_aliases_test.bzl
@@ -419,10 +419,16 @@
alias = _mock_alias(available_config_settings),
config_setting = _mock_config_setting(available_config_settings),
),
- target_platforms = [
- "linux_aarch64",
- "linux_x86_64",
- ],
+ platform_constraint_values = {
+ "linux_aarch64": [
+ "@platforms//cpu:aarch64",
+ "@platforms//os:linux",
+ ],
+ "linux_x86_64": [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:linux",
+ ],
+ },
)
got_aliases = multiplatform_whl_aliases(
@@ -448,19 +454,39 @@
"any": {},
"macosx_11_0_arm64": {
"osx_versions": [(11, 0)],
- "target_platforms": ["osx_aarch64"],
+ "platform_constraint_values": {
+ "osx_aarch64": [
+ "@platforms//cpu:aarch64",
+ "@platforms//os:osx",
+ ],
+ },
},
"manylinux_2_17_x86_64": {
"glibc_versions": [(2, 17), (2, 18)],
- "target_platforms": ["linux_x86_64"],
+ "platform_constraint_values": {
+ "linux_x86_64": [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:linux",
+ ],
+ },
},
"manylinux_2_18_x86_64": {
"glibc_versions": [(2, 17), (2, 18)],
- "target_platforms": ["linux_x86_64"],
+ "platform_constraint_values": {
+ "linux_x86_64": [
+ "@platforms//cpu:x86_64",
+ "@platforms//os:linux",
+ ],
+ },
},
"musllinux_1_1_aarch64": {
"muslc_versions": [(1, 2), (1, 1), (1, 0)],
- "target_platforms": ["linux_aarch64"],
+ "platform_constraint_values": {
+ "linux_aarch64": [
+ "@platforms//cpu:aarch64",
+ "@platforms//os:linux",
+ ],
+ },
},
}.items():
aliases = {
diff --git a/tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl b/tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl
index 416d50b..c262ed6 100644
--- a/tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl
+++ b/tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl
@@ -93,6 +93,12 @@
},
},
extra_hub_aliases = {"bar_baz": ["foo"]},
+ platform_constraint_values = {
+ "linux_x86_64": [
+ "@platforms//os:linux",
+ "@platforms//cpu:x86_64",
+ ],
+ },
)
want_key = "bar_baz/BUILD.bazel"
@@ -130,8 +136,13 @@
config_settings(
name = "config_settings",
+ platform_constraint_values = {
+ "linux_x86_64": [
+ "@platforms//os:linux",
+ "@platforms//cpu:x86_64",
+ ],
+ },
python_versions = ["3.2"],
- target_platforms = ["linux_x86_64"],
visibility = ["//:__subpackages__"],
)""",
)