Skip to content

Commit c86673f

Browse files
committed
fix: use the python micro version to parse whl metadata in bzlmod
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. - [ ] Extra testing to ensure that the default version selection works correctly. - [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] changelog. - [x] `pep508_deps` tests for handling the `full_python_version` correctly. Fixes #2319
1 parent 1d69ad6 commit c86673f

File tree

16 files changed

+145
-55
lines changed

16 files changed

+145
-55
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ END_UNRELEASED_TEMPLATE
6969
* The `sys._base_executable` value will reflect the underlying interpreter,
7070
not venv interpreter.
7171
* The {obj}`//python/runtime_env_toolchains:all` toolchain now works with it.
72+
* (pypi) Correctly handle `METADATA` entries when `python_full_version` is used in
73+
the environment marker.
74+
Fixes [#2319](https://github.com/bazel-contrib/rules_python/issues/2319).
7275

7376
{#v0-0-0-added}
7477
### Added

examples/bzlmod/entry_points/BUILD.bazel

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
load("@python_versions//3.9:defs.bzl", py_console_script_binary_3_9 = "py_console_script_binary")
21
load("@rules_python//python/entry_points:py_console_script_binary.bzl", "py_console_script_binary")
32

43
# This is how you can define a `pylint` entrypoint which uses the default python version.
@@ -24,10 +23,11 @@ py_console_script_binary(
2423
],
2524
)
2625

27-
# A specific Python version can be forced by using the generated version-aware
28-
# wrappers, e.g. to force Python 3.9:
29-
py_console_script_binary_3_9(
26+
# A specific Python version can be forced by passing `python_version`
27+
# attribute, e.g. to force Python 3.9:
28+
py_console_script_binary(
3029
name = "yamllint",
3130
pkg = "@pip//yamllint:pkg",
31+
python_version = "3.9",
3232
visibility = ["//entry_points:__subpackages__"],
3333
)

python/private/pypi/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ bzl_library(
103103
"//python/private:version_label_bzl",
104104
"@bazel_features//:features",
105105
"@pythons_hub//:interpreters_bzl",
106+
"@pythons_hub//:versions_bzl",
106107
],
107108
)
108109

@@ -220,7 +221,9 @@ bzl_library(
220221
":pep508_evaluate_bzl",
221222
":pep508_platform_bzl",
222223
":pep508_requirement_bzl",
224+
"//python/private:full_version_bzl",
223225
"//python/private:normalize_name_bzl",
226+
"@pythons_hub//:versions_bzl",
224227
],
225228
)
226229

python/private/pypi/config_settings.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ specialized is as follows:
4242
* `:is_cp3<minor_version>_abi3_<platform_suffix>`
4343
* `:is_cp3<minor_version>_cp3<minor_version>_<platform_suffix>` and `:is_cp3<minor_version>_cp3<minor_version>t_<platform_suffix>`
4444
45+
Optionally instead of `<minor_version>` there sometimes may be `<minor_version>.<micro_version>` used in order to fully specify the versions
46+
4547
The specialization of free-threaded vs non-free-threaded wheels is the same as
4648
they are just variants of each other. The same goes for the specialization of
4749
`musllinux` vs `manylinux`.

python/private/pypi/extension.bzl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
load("@bazel_features//:features.bzl", "bazel_features")
1818
load("@pythons_hub//:interpreters.bzl", "INTERPRETER_LABELS")
19+
load("@pythons_hub//:versions.bzl", "MINOR_MAPPING")
1920
load("//python/private:auth.bzl", "AUTH_ATTRS")
21+
load("//python/private:full_version.bzl", "full_version")
2022
load("//python/private:normalize_name.bzl", "normalize_name")
2123
load("//python/private:repo_utils.bzl", "repo_utils")
2224
load("//python/private:semver.bzl", "semver")
@@ -68,6 +70,7 @@ def _create_whl_repos(
6870
pip_attr,
6971
whl_overrides,
7072
available_interpreters = INTERPRETER_LABELS,
73+
minor_mapping = MINOR_MAPPING,
7174
get_index_urls = None):
7275
"""create all of the whl repositories
7376
@@ -159,8 +162,10 @@ def _create_whl_repos(
159162
requirements_osx = pip_attr.requirements_darwin,
160163
requirements_windows = pip_attr.requirements_windows,
161164
extra_pip_args = pip_attr.extra_pip_args,
162-
# TODO @aignas 2025-04-15: pass the full version into here
163-
python_version = major_minor,
165+
python_version = full_version(
166+
version = pip_attr.python_version,
167+
minor_mapping = minor_mapping,
168+
),
164169
logger = logger,
165170
),
166171
extra_pip_args = pip_attr.extra_pip_args,
@@ -304,9 +309,6 @@ def _whl_repos(*, requirement, whl_library_args, download_only, netrc, auth_patt
304309
if requirement.extra_pip_args:
305310
args["extra_pip_args"] = requirement.extra_pip_args
306311

307-
if download_only:
308-
args.setdefault("experimental_target_platforms", requirement.target_platforms)
309-
310312
target_platforms = requirement.target_platforms if multiple_requirements_for_whl else []
311313
repo_name = pypi_repo_name(
312314
normalize_name(requirement.distribution),

python/private/pypi/pep508_deps.bzl

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,23 @@
1515
"""This module is for implementing PEP508 compliant METADATA deps parsing.
1616
"""
1717

18-
load("@pythons_hub//:versions.bzl", "DEFAULT_PYTHON_VERSION")
18+
load("@pythons_hub//:versions.bzl", "DEFAULT_PYTHON_VERSION", "MINOR_MAPPING")
19+
load("//python/private:full_version.bzl", "full_version")
1920
load("//python/private:normalize_name.bzl", "normalize_name")
2021
load(":pep508_env.bzl", "env")
2122
load(":pep508_evaluate.bzl", "evaluate")
2223
load(":pep508_platform.bzl", "platform", "platform_from_str")
2324
load(":pep508_requirement.bzl", "requirement")
2425

25-
def deps(name, *, requires_dist, platforms = [], extras = [], excludes = [], default_python_version = None):
26+
def deps(
27+
name,
28+
*,
29+
requires_dist,
30+
platforms = [],
31+
extras = [],
32+
excludes = [],
33+
default_python_version = None,
34+
minor_mapping = MINOR_MAPPING):
2635
"""Parse the RequiresDist from wheel METADATA
2736
2837
Args:
@@ -33,6 +42,9 @@ def deps(name, *, requires_dist, platforms = [], extras = [], excludes = [], def
3342
extras: {type}`list[str]` the requested extras to generate targets for.
3443
platforms: {type}`list[str]` the list of target platform strings.
3544
default_python_version: {type}`str` the host python version.
45+
minor_mapping: {type}`type[str, str]` the minor mapping to use when
46+
resolving to the full python version as DEFAULT_PYTHON_VERSION can by
47+
of format `3.x`.
3648
3749
Returns:
3850
A struct with attributes:
@@ -52,17 +64,22 @@ def deps(name, *, requires_dist, platforms = [], extras = [], excludes = [], def
5264
# drop self edges
5365
excludes = [name] + [normalize_name(x) for x in excludes]
5466

55-
default_python_version = default_python_version or DEFAULT_PYTHON_VERSION
67+
default_python_version = default_python_version or default_python_version
68+
if default_python_version:
69+
# if it is not bzlmod, then DEFAULT_PYTHON_VERSION may be unset
70+
default_python_version = full_version(
71+
version = default_python_version or DEFAULT_PYTHON_VERSION,
72+
minor_mapping = minor_mapping,
73+
)
5674
platforms = [
5775
platform_from_str(p, python_version = default_python_version)
5876
for p in platforms
5977
]
6078

6179
abis = sorted({p.abi: True for p in platforms if p.abi})
6280
if default_python_version and len(abis) > 1:
63-
_, _, minor_version = default_python_version.partition(".")
64-
minor_version, _, _ = minor_version.partition(".")
65-
default_abi = "cp3" + minor_version
81+
_, _, tail = default_python_version.partition(".")
82+
default_abi = "cp3" + tail
6683
elif len(abis) > 1:
6784
fail(
6885
"all python versions need to be specified explicitly, got: {}".format(platforms),

python/private/pypi/pkg_aliases.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ def get_filename_config_settings(
371371

372372
abi = parsed.abi_tag
373373

374+
# TODO @aignas 2025-04-20: test
375+
abi, _, _ = abi.partition(".")
376+
374377
if parsed.platform_tag == "any":
375378
prefixes = ["{}{}_any".format(py, abi)]
376379
else:

python/private/pypi/render_pkg_aliases.bzl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ def render_pkg_aliases(*, aliases, requirement_cycles = None, extra_hub_aliases
143143
files["_groups/BUILD.bazel"] = generate_group_library_build_bazel("", requirement_cycles)
144144
return files
145145

146+
def _major_minor(python_version):
147+
major, _, tail = python_version.partition(".")
148+
minor, _, _ = tail.partition(".")
149+
return "{}.{}".format(major, minor)
150+
151+
def _major_minor_versions(python_versions):
152+
if not python_versions:
153+
return []
154+
155+
# Use a dict as a simple set
156+
return sorted({_major_minor(v): None for v in python_versions})
157+
146158
def render_multiplatform_pkg_aliases(*, aliases, **kwargs):
147159
"""Render the multi-platform pkg aliases.
148160
@@ -174,7 +186,7 @@ def render_multiplatform_pkg_aliases(*, aliases, **kwargs):
174186
glibc_versions = flag_versions.get("glibc_versions", []),
175187
muslc_versions = flag_versions.get("muslc_versions", []),
176188
osx_versions = flag_versions.get("osx_versions", []),
177-
python_versions = flag_versions.get("python_versions", []),
189+
python_versions = _major_minor_versions(flag_versions.get("python_versions", [])),
178190
target_platforms = flag_versions.get("target_platforms", []),
179191
visibility = ["//:__subpackages__"],
180192
)

python/private/pypi/requirements_files_by_platform.bzl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,12 @@ def _platforms_from_args(extra_pip_args):
9191
return list(platforms.keys())
9292

9393
def _platform(platform_string, python_version = None):
94-
if not python_version or platform_string.startswith("cp3"):
94+
if not python_version or platform_string.startswith("cp"):
9595
return platform_string
9696

97-
_, _, tail = python_version.partition(".")
98-
minor, _, _ = tail.partition(".")
97+
major, _, tail = python_version.partition(".")
9998

100-
return "cp3{}_{}".format(minor, platform_string)
99+
return "cp{}{}_{}".format(major, tail, platform_string)
101100

102101
def requirements_files_by_platform(
103102
*,

python/private/pypi/whl_config_setting.bzl

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,20 @@ def whl_config_setting(*, version = None, config_setting = None, filename = None
3535
a struct with the validated and parsed values.
3636
"""
3737
if target_platforms:
38-
for p in target_platforms:
38+
target_platforms_input = target_platforms
39+
target_platforms = []
40+
for p in target_platforms_input:
3941
if not p.startswith("cp"):
4042
fail("target_platform should start with 'cp' denoting the python version, got: " + p)
4143

44+
abi, _, tail = p.partition("_")
45+
46+
# drop the micro version here, currently there is no usecase to use
47+
# multiple python interpreters with the same minor version but
48+
# different micro version.
49+
abi, _, _ = abi.partition(".")
50+
target_platforms.append("{}_{}".format(abi, tail))
51+
4252
return struct(
4353
config_setting = config_setting,
4454
filename = filename,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy