Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ END_UNRELEASED_TEMPLATE
* The {obj}`//python/runtime_env_toolchains:all` toolchain now works with it.
* (rules) Better handle flakey platform.win32_ver() calls by calling them
multiple times.
* (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).

{#v0-0-0-added}
### Added
Expand Down
8 changes: 4 additions & 4 deletions examples/bzlmod/entry_points/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -24,10 +23,11 @@ py_console_script_binary(
],
)

# 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__"],
)
3 changes: 3 additions & 0 deletions python/private/pypi/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ bzl_library(
"//python/private:version_label_bzl",
"@bazel_features//:features",
"@pythons_hub//:interpreters_bzl",
"@pythons_hub//:versions_bzl",
],
)

Expand Down Expand Up @@ -220,7 +221,9 @@ bzl_library(
":pep508_evaluate_bzl",
":pep508_platform_bzl",
":pep508_requirement_bzl",
"//python/private:full_version_bzl",
"//python/private:normalize_name_bzl",
"@pythons_hub//:versions_bzl",
],
)

Expand Down
2 changes: 2 additions & 0 deletions python/private/pypi/config_settings.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ specialized is as follows:
* `: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`.
Expand Down
14 changes: 9 additions & 5 deletions python/private/pypi/extension.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -68,6 +70,7 @@ def _create_whl_repos(
pip_attr,
whl_overrides,
available_interpreters = INTERPRETER_LABELS,
minor_mapping = MINOR_MAPPING,
get_index_urls = None):
"""create all of the whl repositories

Expand All @@ -80,6 +83,8 @@ def _create_whl_repos(
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
Expand Down Expand Up @@ -159,8 +164,10 @@ def _create_whl_repos(
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,
Expand Down Expand Up @@ -304,9 +311,6 @@ def _whl_repos(*, requirement, whl_library_args, download_only, netrc, auth_patt
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),
Expand Down
27 changes: 22 additions & 5 deletions python/private/pypi/pep508_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -33,6 +42,9 @@ def deps(name, *, requires_dist, platforms = [], extras = [], excludes = [], def
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:
Expand All @@ -53,16 +65,21 @@ def deps(name, *, requires_dist, platforms = [], extras = [], excludes = [], def
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
]

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),
Expand Down
3 changes: 3 additions & 0 deletions python/private/pypi/pkg_aliases.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,9 @@ def get_filename_config_settings(

abi = parsed.abi_tag

# TODO @aignas 2025-04-20: test
abi, _, _ = abi.partition(".")

if parsed.platform_tag == "any":
prefixes = ["{}{}_any".format(py, abi)]
else:
Expand Down
14 changes: 13 additions & 1 deletion python/private/pypi/render_pkg_aliases.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,18 @@ def render_pkg_aliases(*, aliases, requirement_cycles = None, extra_hub_aliases
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.

Expand Down Expand Up @@ -174,7 +186,7 @@ def render_multiplatform_pkg_aliases(*, aliases, **kwargs):
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__"],
)
Expand Down
7 changes: 3 additions & 4 deletions python/private/pypi/requirements_files_by_platform.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,12 @@ def _platforms_from_args(extra_pip_args):
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(
*,
Expand Down
12 changes: 11 additions & 1 deletion python/private/pypi/whl_config_setting.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,20 @@ def whl_config_setting(*, version = None, config_setting = None, filename = None
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,
Expand Down
16 changes: 6 additions & 10 deletions python/private/pypi/whl_library_targets.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -369,26 +369,22 @@ def _config_settings(dependencies_by_platform, native = native, **kwargs):
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"):],
),
str(Label("//python/config_settings:python_version")): "3.{}".format(abi[len("cp3"):]),
}

native.config_setting(
Expand Down
5 changes: 4 additions & 1 deletion python/private/pypi/whl_target_platforms.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,11 @@ def select_whls(*, whls, want_platforms = [], logger = None):
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:
Expand Down
Loading