Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ END_UNRELEASED_TEMPLATE
### 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
Expand Down
31 changes: 14 additions & 17 deletions python/private/pypi/config_settings.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ def config_settings(
glibc_versions = [],
muslc_versions = [],
osx_versions = [],
target_platforms = [],
name = None,
platform_constraint_values = {},
**kwargs):
"""Generate all of the pip config settings.

Expand All @@ -126,31 +126,28 @@ def config_settings(
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`.
"""

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,
Expand Down
34 changes: 31 additions & 3 deletions python/private/pypi/extension.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ def _whl_repo(*, src, whl_library_args, is_multiple_versions, download_only, net
),
)

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:
Expand All @@ -387,6 +387,7 @@ def _configure(config, *, platform, os_name, arch_name, override = False, env =
name = platform.replace("-", "_").lower(),
os_name = os_name,
arch_name = arch_name,
constraint_values = constraint_values,
env = env,
)
else:
Expand All @@ -413,6 +414,10 @@ def _create_config(defaults):
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 [
Expand All @@ -424,17 +429,25 @@ def _create_config(defaults):
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)

Expand Down Expand Up @@ -500,6 +513,7 @@ You cannot use both the additive_build_content and additive_build_content_file a
_configure(
defaults,
arch_name = tag.arch_name,
constraint_values = tag.constraint_values,
env = tag.env,
os_name = tag.os_name,
platform = tag.platform,
Expand Down Expand Up @@ -679,6 +693,13 @@ You cannot use both the additive_build_content and additive_build_content_file a
}
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())
Expand Down Expand Up @@ -769,6 +790,7 @@ def _pip_impl(module_ctx):
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),
)

Expand All @@ -788,6 +810,12 @@ The CPU architecture name to be used.
:::{note}
Either this or {attr}`env` `platform_machine` key should be specified.
:::
""",
),
"constraint_values": attr.label_list(
mandatory = True,
doc = """\
The constraint_values to use in select statements.
""",
),
"os_name": attr.string(
Expand Down
5 changes: 5 additions & 0 deletions python/private/pypi/hub_repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def _impl(rctx):
},
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)
Expand Down Expand Up @@ -83,6 +84,10 @@ hub_repository = repository_rule(
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.",
Expand Down
12 changes: 9 additions & 3 deletions python/private/pypi/render_pkg_aliases.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,14 @@ def _major_minor_versions(python_versions):
# 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:
Expand All @@ -187,18 +189,22 @@ def render_multiplatform_pkg_aliases(*, aliases, **kwargs):
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)
))

Expand Down
13 changes: 7 additions & 6 deletions python/private/runtime_env_toolchain_interpreter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,15 @@ if [ -e "$self_dir/pyvenv.cfg" ] || [ -e "$self_dir/../pyvenv.cfg" ]; then
if [ ! -e "$PYTHON_BIN" ]; then
die "ERROR: Python interpreter does not exist: $PYTHON_BIN"
fi
# PYTHONEXECUTABLE is also used because `exec -a` doesn't fully trick the
# pyenv wrappers.
# PYTHONEXECUTABLE is also used because switching argv0 doesn't fully trick
# the pyenv wrappers.
# NOTE: The PYTHONEXECUTABLE envvar only works for non-Mac starting in Python 3.11
export PYTHONEXECUTABLE="$venv_bin"
# Python looks at argv[0] to determine sys.executable, so use exec -a
# to make it think it's the venv's binary, not the actual one invoked.
# NOTE: exec -a isn't strictly posix-compatible, but very widespread
exec -a "$venv_bin" "$PYTHON_BIN" "$@"
# Python looks at argv[0] to determine sys.executable, so set that to the venv
# binary, not the actual one invoked.
# NOTE: exec -a would be simpler, but isn't posix-compatible, and dash shell
# (Ubuntu/debian default) doesn't support it; see #3009.
exec sh -c "$PYTHON_BIN \$@" "$venv_bin" "$@"
else
exec "$PYTHON_BIN" "$@"
fi
39 changes: 30 additions & 9 deletions tests/pypi/config_settings/config_settings_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -657,13 +657,34 @@ def config_settings_test_suite(name): # buildifier: disable=function-docstring
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",
],
},
)
4 changes: 4 additions & 0 deletions tests/pypi/extension/extension_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,10 @@ def _test_pipstar_platforms(env):
default = [
_default(
platform = "{}_{}".format(os, cpu),
constraint_values = [
"@platforms//os:{}".format(os),
"@platforms//cpu:{}".format(cpu),
],
)
for os, cpu in [
("linux", "x86_64"),
Expand Down
42 changes: 34 additions & 8 deletions tests/pypi/pkg_aliases/pkg_aliases_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,16 @@ def _test_config_settings_exist_legacy(env):
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(
Expand All @@ -448,19 +454,39 @@ def _test_config_settings_exist(env):
"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 = {
Expand Down
13 changes: 12 additions & 1 deletion tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ def _test_bzlmod_aliases(env):
},
},
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"
Expand Down Expand Up @@ -130,8 +136,13 @@ load("@rules_python//python/private/pypi:config_settings.bzl", "config_settings"

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__"],
)""",
)
Expand Down
Loading