fix: use the python micro version to parse whl metadata in bzlmod (#2793)
Add `<micro>` version to the target platform. Instead of `cpxy_os_cpu`
the target platform string format becomes `cpxy.z_os_cpu`. This is a
temporary measure until we get a better API for defining target
platforms.
Summary:
- [x] test `select_whls` function needs to be tested to ensure that the
whl selection is not impacted when we have the full version in the
target platform.
- [ ] `download_only` legacy whl code path in `bzlmod` needs further
testing.
- [x] test `whl_config_setting` handling and config setting creation.
The config settings in the hub repo should not use the full version,
because from the outside, the whl is compatible with all `micro`
versions of a given `3.<minor_version>` of the Python interpreter.
This means that the already documented config setting do not need to
be changed.
- [x] `pep508_deps` tests for handling the `full_python_version`
correctly.
- [x] `pep508_deps` tests for ensuring the `default_abi` is being
handled correctly.
Fixes #2319
diff --git a/.bazelrc b/.bazelrc
index d2e0721..4e6f2fa 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -4,8 +4,8 @@
# (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it)
# To update these lines, execute
# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
-build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/python/private,gazelle/pythonconfig,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma
-query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/python/private,gazelle/pythonconfig,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma
+build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma
+query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered,tests/modules/other,tests/modules/other/nspkg_delta,tests/modules/other/nspkg_gamma
test --test_output=errors
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 88defb8..984af8b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -148,6 +148,9 @@
* (packaging) An empty `requires_file` is treated as if it were omitted, resulting in a valid `METADATA` file.
* (rules) py_wheel and sphinxdocs rules now propagate `target_compatible_with` to all targets they create.
[PR #2788](https://github.com/bazel-contrib/rules_python/pull/2788).
+* (pypi) Correctly handle `METADATA` entries when `python_full_version` is used in
+ the environment marker.
+ Fixes [#2319](https://github.com/bazel-contrib/rules_python/issues/2319).
{#1-4-0-added}
### Added
diff --git a/examples/bzlmod/entry_points/BUILD.bazel b/examples/bzlmod/entry_points/BUILD.bazel
index a0939cb..4ca5b53 100644
--- a/examples/bzlmod/entry_points/BUILD.bazel
+++ b/examples/bzlmod/entry_points/BUILD.bazel
@@ -1,4 +1,3 @@
-load("@python_versions//3.9:defs.bzl", py_console_script_binary_3_9 = "py_console_script_binary")
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
# This is how you can define a `pylint` entrypoint which uses the default python version.
@@ -24,10 +23,11 @@
],
)
-# A specific Python version can be forced by using the generated version-aware
-# wrappers, e.g. to force Python 3.9:
-py_console_script_binary_3_9(
+# A specific Python version can be forced by passing `python_version`
+# attribute, e.g. to force Python 3.9:
+py_console_script_binary(
name = "yamllint",
pkg = "@pip//yamllint:pkg",
+ python_version = "3.9",
visibility = ["//entry_points:__subpackages__"],
)
diff --git a/python/private/pypi/BUILD.bazel b/python/private/pypi/BUILD.bazel
index a758b3f..bfb0be2 100644
--- a/python/private/pypi/BUILD.bazel
+++ b/python/private/pypi/BUILD.bazel
@@ -103,6 +103,7 @@
"//python/private:version_label_bzl",
"@bazel_features//:features",
"@pythons_hub//:interpreters_bzl",
+ "@pythons_hub//:versions_bzl",
],
)
@@ -220,7 +221,9 @@
":pep508_evaluate_bzl",
":pep508_platform_bzl",
":pep508_requirement_bzl",
+ "//python/private:full_version_bzl",
"//python/private:normalize_name_bzl",
+ "@pythons_hub//:versions_bzl",
],
)
diff --git a/python/private/pypi/config_settings.bzl b/python/private/pypi/config_settings.bzl
index 1045ffe..d1b85d1 100644
--- a/python/private/pypi/config_settings.bzl
+++ b/python/private/pypi/config_settings.bzl
@@ -42,6 +42,8 @@
* `:is_cp3<minor_version>_abi3_<platform_suffix>`
* `:is_cp3<minor_version>_cp3<minor_version>_<platform_suffix>` and `:is_cp3<minor_version>_cp3<minor_version>t_<platform_suffix>`
+Optionally instead of `<minor_version>` there sometimes may be `<minor_version>.<micro_version>` used in order to fully specify the versions
+
The specialization of free-threaded vs non-free-threaded wheels is the same as
they are just variants of each other. The same goes for the specialization of
`musllinux` vs `manylinux`.
diff --git a/python/private/pypi/extension.bzl b/python/private/pypi/extension.bzl
index d1895ca..e9eba68 100644
--- a/python/private/pypi/extension.bzl
+++ b/python/private/pypi/extension.bzl
@@ -16,7 +16,9 @@
load("@bazel_features//:features.bzl", "bazel_features")
load("@pythons_hub//:interpreters.bzl", "INTERPRETER_LABELS")
+load("@pythons_hub//:versions.bzl", "MINOR_MAPPING")
load("//python/private:auth.bzl", "AUTH_ATTRS")
+load("//python/private:full_version.bzl", "full_version")
load("//python/private:normalize_name.bzl", "normalize_name")
load("//python/private:repo_utils.bzl", "repo_utils")
load("//python/private:semver.bzl", "semver")
@@ -68,6 +70,7 @@
pip_attr,
whl_overrides,
available_interpreters = INTERPRETER_LABELS,
+ minor_mapping = MINOR_MAPPING,
get_index_urls = None):
"""create all of the whl repositories
@@ -80,6 +83,8 @@
interpreters that have been registered using the `python` bzlmod extension.
The keys are in the form `python_{snake_case_version}_host`. This is to be
used during the `repository_rule` and must be always compatible with the host.
+ minor_mapping: {type}`dict[str, str]` The dictionary needed to resolve the full
+ python version used to parse package METADATA files.
Returns a {type}`struct` with the following attributes:
whl_map: {type}`dict[str, list[struct]]` the output is keyed by the
@@ -159,8 +164,10 @@
requirements_osx = pip_attr.requirements_darwin,
requirements_windows = pip_attr.requirements_windows,
extra_pip_args = pip_attr.extra_pip_args,
- # TODO @aignas 2025-04-15: pass the full version into here
- python_version = major_minor,
+ python_version = full_version(
+ version = pip_attr.python_version,
+ minor_mapping = minor_mapping,
+ ),
logger = logger,
),
extra_pip_args = pip_attr.extra_pip_args,
@@ -304,9 +311,6 @@
if requirement.extra_pip_args:
args["extra_pip_args"] = requirement.extra_pip_args
- if download_only:
- args.setdefault("experimental_target_platforms", requirement.target_platforms)
-
target_platforms = requirement.target_platforms if multiple_requirements_for_whl else []
repo_name = pypi_repo_name(
normalize_name(requirement.distribution),
diff --git a/python/private/pypi/pep508_deps.bzl b/python/private/pypi/pep508_deps.bzl
index 115bbd7..bcc4845 100644
--- a/python/private/pypi/pep508_deps.bzl
+++ b/python/private/pypi/pep508_deps.bzl
@@ -15,14 +15,23 @@
"""This module is for implementing PEP508 compliant METADATA deps parsing.
"""
-load("@pythons_hub//:versions.bzl", "DEFAULT_PYTHON_VERSION")
+load("@pythons_hub//:versions.bzl", "DEFAULT_PYTHON_VERSION", "MINOR_MAPPING")
+load("//python/private:full_version.bzl", "full_version")
load("//python/private:normalize_name.bzl", "normalize_name")
load(":pep508_env.bzl", "env")
load(":pep508_evaluate.bzl", "evaluate")
load(":pep508_platform.bzl", "platform", "platform_from_str")
load(":pep508_requirement.bzl", "requirement")
-def deps(name, *, requires_dist, platforms = [], extras = [], excludes = [], default_python_version = None):
+def deps(
+ name,
+ *,
+ requires_dist,
+ platforms = [],
+ extras = [],
+ excludes = [],
+ default_python_version = None,
+ minor_mapping = MINOR_MAPPING):
"""Parse the RequiresDist from wheel METADATA
Args:
@@ -33,6 +42,9 @@
extras: {type}`list[str]` the requested extras to generate targets for.
platforms: {type}`list[str]` the list of target platform strings.
default_python_version: {type}`str` the host python version.
+ minor_mapping: {type}`type[str, str]` the minor mapping to use when
+ resolving to the full python version as DEFAULT_PYTHON_VERSION can by
+ of format `3.x`.
Returns:
A struct with attributes:
@@ -53,6 +65,12 @@
excludes = [name] + [normalize_name(x) for x in excludes]
default_python_version = default_python_version or DEFAULT_PYTHON_VERSION
+ if default_python_version:
+ # if it is not bzlmod, then DEFAULT_PYTHON_VERSION may be unset
+ default_python_version = full_version(
+ version = default_python_version,
+ minor_mapping = minor_mapping,
+ )
platforms = [
platform_from_str(p, python_version = default_python_version)
for p in platforms
@@ -60,9 +78,8 @@
abis = sorted({p.abi: True for p in platforms if p.abi})
if default_python_version and len(abis) > 1:
- _, _, minor_version = default_python_version.partition(".")
- minor_version, _, _ = minor_version.partition(".")
- default_abi = "cp3" + minor_version
+ _, _, tail = default_python_version.partition(".")
+ default_abi = "cp3" + tail
elif len(abis) > 1:
fail(
"all python versions need to be specified explicitly, got: {}".format(platforms),
diff --git a/python/private/pypi/pkg_aliases.bzl b/python/private/pypi/pkg_aliases.bzl
index a9eee7b..28d70ff 100644
--- a/python/private/pypi/pkg_aliases.bzl
+++ b/python/private/pypi/pkg_aliases.bzl
@@ -371,6 +371,9 @@
abi = parsed.abi_tag
+ # TODO @aignas 2025-04-20: test
+ abi, _, _ = abi.partition(".")
+
if parsed.platform_tag == "any":
prefixes = ["{}{}_any".format(py, abi)]
else:
diff --git a/python/private/pypi/render_pkg_aliases.bzl b/python/private/pypi/render_pkg_aliases.bzl
index 863d250..28f32ed 100644
--- a/python/private/pypi/render_pkg_aliases.bzl
+++ b/python/private/pypi/render_pkg_aliases.bzl
@@ -143,6 +143,18 @@
files["_groups/BUILD.bazel"] = generate_group_library_build_bazel("", requirement_cycles)
return files
+def _major_minor(python_version):
+ major, _, tail = python_version.partition(".")
+ minor, _, _ = tail.partition(".")
+ return "{}.{}".format(major, minor)
+
+def _major_minor_versions(python_versions):
+ if not python_versions:
+ return []
+
+ # 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):
"""Render the multi-platform pkg aliases.
@@ -174,7 +186,7 @@
glibc_versions = flag_versions.get("glibc_versions", []),
muslc_versions = flag_versions.get("muslc_versions", []),
osx_versions = flag_versions.get("osx_versions", []),
- python_versions = flag_versions.get("python_versions", []),
+ python_versions = _major_minor_versions(flag_versions.get("python_versions", [])),
target_platforms = flag_versions.get("target_platforms", []),
visibility = ["//:__subpackages__"],
)
diff --git a/python/private/pypi/requirements_files_by_platform.bzl b/python/private/pypi/requirements_files_by_platform.bzl
index e3aafc0..9165c05 100644
--- a/python/private/pypi/requirements_files_by_platform.bzl
+++ b/python/private/pypi/requirements_files_by_platform.bzl
@@ -91,13 +91,12 @@
return list(platforms.keys())
def _platform(platform_string, python_version = None):
- if not python_version or platform_string.startswith("cp3"):
+ if not python_version or platform_string.startswith("cp"):
return platform_string
- _, _, tail = python_version.partition(".")
- minor, _, _ = tail.partition(".")
+ major, _, tail = python_version.partition(".")
- return "cp3{}_{}".format(minor, platform_string)
+ return "cp{}{}_{}".format(major, tail, platform_string)
def requirements_files_by_platform(
*,
diff --git a/python/private/pypi/whl_config_setting.bzl b/python/private/pypi/whl_config_setting.bzl
index d966206..6e10eb4 100644
--- a/python/private/pypi/whl_config_setting.bzl
+++ b/python/private/pypi/whl_config_setting.bzl
@@ -35,10 +35,20 @@
a struct with the validated and parsed values.
"""
if target_platforms:
- for p in target_platforms:
+ target_platforms_input = target_platforms
+ target_platforms = []
+ for p in target_platforms_input:
if not p.startswith("cp"):
fail("target_platform should start with 'cp' denoting the python version, got: " + p)
+ abi, _, tail = p.partition("_")
+
+ # drop the micro version here, currently there is no usecase to use
+ # multiple python interpreters with the same minor version but
+ # different micro version.
+ abi, _, _ = abi.partition(".")
+ target_platforms.append("{}_{}".format(abi, tail))
+
return struct(
config_setting = config_setting,
filename = filename,
diff --git a/python/private/pypi/whl_library_targets.bzl b/python/private/pypi/whl_library_targets.bzl
index cf3df13..21e4a54 100644
--- a/python/private/pypi/whl_library_targets.bzl
+++ b/python/private/pypi/whl_library_targets.bzl
@@ -369,26 +369,22 @@
if p.startswith("@") or p.endswith("default"):
continue
+ # TODO @aignas 2025-04-20: add tests here
abi, _, tail = p.partition("_")
if not abi.startswith("cp"):
tail = p
abi = ""
-
os, _, arch = tail.partition("_")
- os = "" if os == "anyos" else os
- arch = "" if arch == "anyarch" else arch
_kwargs = dict(kwargs)
- if arch:
- _kwargs.setdefault("constraint_values", []).append("@platforms//cpu:{}".format(arch))
- if os:
- _kwargs.setdefault("constraint_values", []).append("@platforms//os:{}".format(os))
+ _kwargs["constraint_values"] = [
+ "@platforms//cpu:{}".format(arch),
+ "@platforms//os:{}".format(os),
+ ]
if abi:
_kwargs["flag_values"] = {
- "@rules_python//python/config_settings:python_version_major_minor": "3.{minor_version}".format(
- minor_version = abi[len("cp3"):],
- ),
+ Label("//python/config_settings:python_version"): "3.{}".format(abi[len("cp3"):]),
}
native.config_setting(
diff --git a/python/private/pypi/whl_target_platforms.bzl b/python/private/pypi/whl_target_platforms.bzl
index 9f47e62..6ea3f12 100644
--- a/python/private/pypi/whl_target_platforms.bzl
+++ b/python/private/pypi/whl_target_platforms.bzl
@@ -75,8 +75,11 @@
fail("expected all platforms to start with ABI, but got: {}".format(p))
abi, _, os_cpu = p.partition("_")
+ abi, _, _ = abi.partition(".")
_want_platforms[os_cpu] = None
- _want_platforms[p] = None
+
+ # TODO @aignas 2025-04-20: add a test
+ _want_platforms["{}_{}".format(abi, os_cpu)] = None
version_limit_candidate = int(abi[3:])
if not version_limit:
diff --git a/tests/pypi/extension/extension_tests.bzl b/tests/pypi/extension/extension_tests.bzl
index ce5474e..5de3bb58 100644
--- a/tests/pypi/extension/extension_tests.bzl
+++ b/tests/pypi/extension/extension_tests.bzl
@@ -157,6 +157,7 @@
available_interpreters = {
"python_3_15_host": "unit_test_interpreter_target",
},
+ minor_mapping = {"3.15": "3.15.19"},
)
pypi.exposed_packages().contains_exactly({"pypi": ["simple"]})
@@ -204,6 +205,7 @@
available_interpreters = {
"python_3_15_host": "unit_test_interpreter_target",
},
+ minor_mapping = {"3.15": "3.15.19"},
)
pypi.exposed_packages().contains_exactly({"pypi": ["simple"]})
@@ -270,6 +272,7 @@
available_interpreters = {
"python_3_15_host": "unit_test_interpreter_target",
},
+ minor_mapping = {"3.15": "3.15.19"},
)
pypi.exposed_packages().contains_exactly({"pypi": ["torch"]})
@@ -392,6 +395,7 @@
available_interpreters = {
"python_3_12_host": "unit_test_interpreter_target",
},
+ minor_mapping = {"3.12": "3.12.19"},
simpleapi_download = mocksimpleapi_download,
)
@@ -515,6 +519,7 @@
available_interpreters = {
"python_3_15_host": "unit_test_interpreter_target",
},
+ minor_mapping = {"3.15": "3.15.19"},
)
pypi.exposed_packages().contains_exactly({"pypi": ["simple"]})
@@ -544,7 +549,8 @@
"pypi_315_extra": {
"dep_template": "@pypi//{name}:{target}",
"download_only": True,
- "experimental_target_platforms": ["cp315_linux_x86_64"],
+ # TODO @aignas 2025-04-20: ensure that this is in the hub repo
+ # "experimental_target_platforms": ["cp315_linux_x86_64"],
"extra_pip_args": ["--platform=manylinux_2_17_x86_64", "--python-version=315", "--implementation=cp", "--abi=cp315"],
"python_interpreter_target": "unit_test_interpreter_target",
"requirement": "extra==0.0.1 --hash=sha256:deadb00f",
@@ -552,7 +558,6 @@
"pypi_315_simple_linux_x86_64": {
"dep_template": "@pypi//{name}:{target}",
"download_only": True,
- "experimental_target_platforms": ["cp315_linux_x86_64"],
"extra_pip_args": ["--platform=manylinux_2_17_x86_64", "--python-version=315", "--implementation=cp", "--abi=cp315"],
"python_interpreter_target": "unit_test_interpreter_target",
"requirement": "simple==0.0.1 --hash=sha256:deadbeef",
@@ -560,7 +565,6 @@
"pypi_315_simple_osx_aarch64": {
"dep_template": "@pypi//{name}:{target}",
"download_only": True,
- "experimental_target_platforms": ["cp315_osx_aarch64"],
"extra_pip_args": ["--platform=macosx_10_9_arm64", "--python-version=315", "--implementation=cp", "--abi=cp315"],
"python_interpreter_target": "unit_test_interpreter_target",
"requirement": "simple==0.0.3 --hash=sha256:deadbaaf",
@@ -648,6 +652,7 @@
available_interpreters = {
"python_3_15_host": "unit_test_interpreter_target",
},
+ minor_mapping = {"3.15": "3.15.19"},
simpleapi_download = mocksimpleapi_download,
)
@@ -850,6 +855,7 @@
available_interpreters = {
"python_3_15_host": "unit_test_interpreter_target",
},
+ minor_mapping = {"3.15": "3.15.19"},
)
pypi.exposed_packages().contains_exactly({"pypi": []})
diff --git a/tests/pypi/pep508/deps_tests.bzl b/tests/pypi/pep508/deps_tests.bzl
index d362925..118cd50 100644
--- a/tests/pypi/pep508/deps_tests.bzl
+++ b/tests/pypi/pep508/deps_tests.bzl
@@ -48,6 +48,15 @@
],
python_version = "",
),
+ struct(
+ platforms = [
+ "cp33.1_linux_x86_64",
+ "cp33.1_osx_x86_64",
+ "cp33.1_osx_aarch64",
+ "cp33.1_windows_x86_64",
+ ],
+ python_version = "",
+ ),
]:
got = deps(
"foo",
@@ -154,7 +163,7 @@
def _test_can_get_deps_based_on_specific_python_version(env):
requires_dist = [
"bar",
- "baz; python_version < '3.8'",
+ "baz; python_full_version < '3.7.3'",
"posix_dep; os_name=='posix' and python_version >= '3.8'",
]
@@ -163,6 +172,11 @@
requires_dist = requires_dist,
platforms = ["cp38_linux_x86_64"],
)
+ py373 = deps(
+ "foo",
+ requires_dist = requires_dist,
+ platforms = ["cp37.3_linux_x86_64"],
+ )
py37 = deps(
"foo",
requires_dist = requires_dist,
@@ -174,6 +188,8 @@
env.expect.that_dict(py37.deps_select).contains_exactly({})
env.expect.that_collection(py38.deps).contains_exactly(["bar", "posix_dep"])
env.expect.that_dict(py38.deps_select).contains_exactly({})
+ env.expect.that_collection(py373.deps).contains_exactly(["bar"])
+ env.expect.that_dict(py373.deps_select).contains_exactly({})
_tests.append(_test_can_get_deps_based_on_specific_python_version)
@@ -210,27 +226,29 @@
"posix_dep_with_version; os_name=='posix' and python_version >= '3.8'",
"arch_dep; platform_machine=='x86_64' and python_version < '3.8'",
]
- default_python_version = "3.7.4"
got = deps(
"foo",
requires_dist = requires_dist,
platforms = [
"cp3{}_{}_x86_64".format(minor, os)
- for minor in [7, 8, 9]
+ for minor in ["7.4", "8.8", "9.8"]
for os in ["linux", "windows"]
],
- default_python_version = default_python_version,
+ default_python_version = "3.7",
+ minor_mapping = {
+ "3.7": "3.7.4",
+ },
)
env.expect.that_collection(got.deps).contains_exactly(["bar"])
env.expect.that_dict(got.deps_select).contains_exactly({
- "cp37_linux_x86_64": ["arch_dep", "baz", "posix_dep"],
- "cp37_windows_x86_64": ["arch_dep", "baz"],
- "cp38_linux_x86_64": ["baz_new", "posix_dep", "posix_dep_with_version"],
- "cp38_windows_x86_64": ["baz_new"],
- "cp39_linux_x86_64": ["baz_new", "posix_dep", "posix_dep_with_version"],
- "cp39_windows_x86_64": ["baz_new"],
+ "cp37.4_linux_x86_64": ["arch_dep", "baz", "posix_dep"],
+ "cp37.4_windows_x86_64": ["arch_dep", "baz"],
+ "cp38.8_linux_x86_64": ["baz_new", "posix_dep", "posix_dep_with_version"],
+ "cp38.8_windows_x86_64": ["baz_new"],
+ "cp39.8_linux_x86_64": ["baz_new", "posix_dep", "posix_dep_with_version"],
+ "cp39.8_windows_x86_64": ["baz_new"],
"linux_x86_64": ["arch_dep", "baz", "posix_dep"],
"windows_x86_64": ["arch_dep", "baz"],
})
@@ -294,8 +312,6 @@
_tests.append(_test_deps_are_not_duplicated)
def _test_deps_are_not_duplicated_when_encountering_platform_dep_first(env):
- default_python_version = "3.7.1"
-
# Note, that we are sorting the incoming `requires_dist` and we need to ensure that we are not getting any
# issues even if the platform-specific line comes first.
requires_dist = [
@@ -307,19 +323,20 @@
"foo",
requires_dist = requires_dist,
platforms = [
- "cp37_linux_aarch64",
- "cp37_linux_x86_64",
+ "cp37.1_linux_aarch64",
+ "cp37.1_linux_x86_64",
"cp310_linux_aarch64",
"cp310_linux_x86_64",
],
- default_python_version = default_python_version,
+ default_python_version = "3.7.1",
+ minor_mapping = {},
)
env.expect.that_collection(got.deps).contains_exactly([])
env.expect.that_dict(got.deps_select).contains_exactly({
"cp310_linux_aarch64": ["bar"],
"cp310_linux_x86_64": ["bar"],
- "cp37_linux_aarch64": ["bar"],
+ "cp37.1_linux_aarch64": ["bar"],
"linux_aarch64": ["bar"],
})
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 c60761b..416d50b 100644
--- a/tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl
+++ b/tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl
@@ -68,7 +68,8 @@
aliases = {
"bar-baz": {
whl_config_setting(
- version = "3.2",
+ # Add one with micro version to mimic construction in the extension
+ version = "3.2.2",
config_setting = "//:my_config_setting",
): "pypi_32_bar_baz",
whl_config_setting(
@@ -83,10 +84,10 @@
filename = "foo-0.0.0-py3-none-any.whl",
): "filename_repo",
whl_config_setting(
- version = "3.2",
+ version = "3.2.2",
filename = "foo-0.0.0-py3-none-any.whl",
target_platforms = [
- "cp32_linux_x86_64",
+ "cp32.2_linux_x86_64",
],
): "filename_repo_linux_x86_64",
},
@@ -117,7 +118,7 @@
whl_config_setting(
filename = "foo-0.0.0-py3-none-any.whl",
target_platforms = ("cp32_linux_x86_64",),
- version = "3.2",
+ version = "3.2.2",
): "filename_repo_linux_x86_64",
},
extra_aliases = ["foo"],
diff --git a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl
index 61e5441..432cdbf 100644
--- a/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl
+++ b/tests/pypi/whl_library_targets/whl_library_targets_tests.bzl
@@ -68,9 +68,8 @@
"@//python/config_settings:is_python_3.9": ["py39_dep"],
"@platforms//cpu:aarch64": ["arm_dep"],
"@platforms//os:windows": ["win_dep"],
+ "cp310.11_linux_ppc64le": ["full_version_dep"],
"cp310_linux_ppc64le": ["py310_linux_ppc64le_dep"],
- "cp39_anyos_aarch64": ["py39_arm_dep"],
- "cp39_linux_anyarch": ["py39_linux_dep"],
"linux_x86_64": ["linux_intel_dep"],
},
filegroups = {},
@@ -82,39 +81,34 @@
env.expect.that_collection(calls).contains_exactly([
{
- "name": "is_python_3.10_linux_ppc64le",
- "flag_values": {
- "@rules_python//python/config_settings:python_version_major_minor": "3.10",
- },
+ "name": "is_python_3.10.11_linux_ppc64le",
+ "visibility": ["//visibility:private"],
"constraint_values": [
"@platforms//cpu:ppc64le",
"@platforms//os:linux",
],
- "visibility": ["//visibility:private"],
+ "flag_values": {
+ Label("//python/config_settings:python_version"): "3.10.11",
+ },
},
{
- "name": "is_python_3.9_anyos_aarch64",
- "flag_values": {
- "@rules_python//python/config_settings:python_version_major_minor": "3.9",
- },
- "constraint_values": ["@platforms//cpu:aarch64"],
+ "name": "is_python_3.10_linux_ppc64le",
"visibility": ["//visibility:private"],
- },
- {
- "name": "is_python_3.9_linux_anyarch",
+ "constraint_values": [
+ "@platforms//cpu:ppc64le",
+ "@platforms//os:linux",
+ ],
"flag_values": {
- "@rules_python//python/config_settings:python_version_major_minor": "3.9",
+ Label("//python/config_settings:python_version"): "3.10",
},
- "constraint_values": ["@platforms//os:linux"],
- "visibility": ["//visibility:private"],
},
{
"name": "is_linux_x86_64",
+ "visibility": ["//visibility:private"],
"constraint_values": [
"@platforms//cpu:x86_64",
"@platforms//os:linux",
],
- "visibility": ["//visibility:private"],
},
]) # buildifier: @unsorted-dict-items
diff --git a/tests/pypi/whl_target_platforms/select_whl_tests.bzl b/tests/pypi/whl_target_platforms/select_whl_tests.bzl
index 8ab2413..1674ac5 100644
--- a/tests/pypi/whl_target_platforms/select_whl_tests.bzl
+++ b/tests/pypi/whl_target_platforms/select_whl_tests.bzl
@@ -289,6 +289,22 @@
_tests.append(_test_freethreaded_wheels)
+def _test_micro_version_freethreaded(env):
+ # Check we prefer platform specific wheels
+ got = _select_whls(whls = WHL_LIST, want_platforms = ["cp313.3_linux_x86_64"])
+ _match(
+ env,
+ got,
+ "pkg-0.0.1-cp313-cp313t-musllinux_1_1_x86_64.whl",
+ "pkg-0.0.1-cp313-cp313-musllinux_1_1_x86_64.whl",
+ "pkg-0.0.1-cp313-abi3-musllinux_1_1_x86_64.whl",
+ "pkg-0.0.1-cp313-none-musllinux_1_1_x86_64.whl",
+ "pkg-0.0.1-cp39-abi3-any.whl",
+ "pkg-0.0.1-py3-none-any.whl",
+ )
+
+_tests.append(_test_micro_version_freethreaded)
+
def select_whl_test_suite(name):
"""Create the test suite.