fix(bzlmod): use X.Y select for the hub repo (#1696)
This allows better interoperability between toolchains and the wheels
built by the `whl_library`, as wheels are usually compatible across all
of the python patch versions.
---------
Co-authored-by: Richard Levasseur <rlevasseur@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c689e9d..66f0fc9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,10 @@
* **BREAKING** (wheel) The `incompatible_normalize_name` and
`incompatible_normalize_version` flags have been removed. They had been
flipped to `True` in 0.27.0 release.
+* (bzlmod) The pip hub repository now uses the newly introduced config settings
+ using the `X.Y` python version notation. This improves cross module
+ interoperability and allows to share wheels built by interpreters using
+ different patch versions.
### Fixed
diff --git a/examples/multi_python_versions/tests/my_lib_test.py b/examples/multi_python_versions/tests/my_lib_test.py
index 1d4880f..3f334f5 100644
--- a/examples/multi_python_versions/tests/my_lib_test.py
+++ b/examples/multi_python_versions/tests/my_lib_test.py
@@ -23,5 +23,7 @@
if not my_lib.websockets_is_for_python_version(
workspace_version
) and not my_lib.websockets_is_for_python_version(bzlmod_version):
- print("expected package for Python version is different than returned")
+ print("expected package for Python version is different than returned\n"
+ f"expected either {workspace_version} or {bzlmod_version}\n"
+ f"but got {my_lib.websockets.__file__}")
sys.exit(1)
diff --git a/python/config_settings/config_settings.bzl b/python/config_settings/config_settings.bzl
index bd4a1b2..f1e142c 100644
--- a/python/config_settings/config_settings.bzl
+++ b/python/config_settings/config_settings.bzl
@@ -29,6 +29,7 @@
# Maps e.g. "3.8" -> ["3.8.1", "3.8.2", etc]
minor_to_micro_versions = {}
+
allowed_flag_values = []
for micro_version in python_versions:
minor, _, _ = micro_version.rpartition(".")
@@ -37,9 +38,12 @@
string_flag(
name = "python_version",
- # TODO: The default here should somehow match the MODULE config
- build_setting_default = python_versions[0],
- values = sorted(allowed_flag_values),
+ # TODO: The default here should somehow match the MODULE config. Until
+ # then, use the empty string to indicate an unknown version. This
+ # also prevents version-unaware targets from inadvertently matching
+ # a select condition when they shouldn't.
+ build_setting_default = "",
+ values = [""] + sorted(allowed_flag_values),
visibility = ["//visibility:public"],
)
@@ -53,7 +57,6 @@
name = equals_minor_version_name,
flag_values = {":python_version": minor_version},
)
-
matches_minor_version_names = [equals_minor_version_name]
for micro_version in micro_versions:
diff --git a/python/private/bzlmod/pip.bzl b/python/private/bzlmod/pip.bzl
index ae19dad..ce3ddde 100644
--- a/python/private/bzlmod/pip.bzl
+++ b/python/private/bzlmod/pip.bzl
@@ -25,12 +25,29 @@
"whl_library",
)
load("//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
-load("//python/private:full_version.bzl", "full_version")
load("//python/private:normalize_name.bzl", "normalize_name")
load("//python/private:parse_whl_name.bzl", "parse_whl_name")
load("//python/private:version_label.bzl", "version_label")
load(":pip_repository.bzl", "pip_repository")
+def _parse_version(version):
+ major, _, version = version.partition(".")
+ minor, _, version = version.partition(".")
+ patch, _, version = version.partition(".")
+ build, _, version = version.partition(".")
+
+ return struct(
+ # use semver vocabulary here
+ major = major,
+ minor = minor,
+ patch = patch, # this is called `micro` in the Python interpreter versioning scheme
+ build = build,
+ )
+
+def _major_minor_version(version):
+ version = _parse_version(version)
+ return "{}.{}".format(version.major, version.minor)
+
def _whl_mods_impl(mctx):
"""Implementation of the pip.whl_mods tag class.
@@ -190,7 +207,7 @@
if whl_name not in whl_map[hub_name]:
whl_map[hub_name][whl_name] = {}
- whl_map[hub_name][whl_name][full_version(pip_attr.python_version)] = pip_name + "_"
+ whl_map[hub_name][whl_name][_major_minor_version(pip_attr.python_version)] = pip_name + "_"
def _pip_impl(module_ctx):
"""Implementation of a class tag that creates the pip hub and corresponding pip spoke whl repositories.
@@ -341,7 +358,7 @@
name = hub_name,
repo_name = hub_name,
whl_map = whl_map,
- default_version = full_version(DEFAULT_PYTHON_VERSION),
+ default_version = _major_minor_version(DEFAULT_PYTHON_VERSION),
)
def _pip_parse_ext_attrs():
diff --git a/python/private/bzlmod/pip_repository.bzl b/python/private/bzlmod/pip_repository.bzl
index 9e6b0f4..8ea5ee7 100644
--- a/python/private/bzlmod/pip_repository.bzl
+++ b/python/private/bzlmod/pip_repository.bzl
@@ -63,7 +63,7 @@
"default_version": attr.string(
mandatory = True,
doc = """\
-This is the default python version in the format of X.Y.Z. This should match
+This is the default python version in the format of X.Y. This should match
what is setup by the 'python' extension using the 'is_default = True'
setting.""",
),
diff --git a/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl b/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl
index dff7cd0..3f99ef3 100644
--- a/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl
+++ b/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl
@@ -73,11 +73,11 @@
def _test_bzlmod_aliases(env):
actual = render_pkg_aliases(
- default_version = "3.2.3",
+ default_version = "3.2",
repo_name = "pypi",
rules_python = "rules_python",
whl_map = {
- "bar-baz": ["3.2.3"],
+ "bar-baz": ["3.2"],
},
)
@@ -94,7 +94,7 @@
name = "pkg",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg",
"//conditions:default": "@pypi_32_bar_baz//:pkg",
},
),
@@ -104,7 +104,7 @@
name = "whl",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl",
"//conditions:default": "@pypi_32_bar_baz//:whl",
},
),
@@ -114,7 +114,7 @@
name = "data",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data",
"//conditions:default": "@pypi_32_bar_baz//:data",
},
),
@@ -124,7 +124,7 @@
name = "dist_info",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info",
"//conditions:default": "@pypi_32_bar_baz//:dist_info",
},
),
@@ -141,7 +141,7 @@
repo_name = "pypi",
rules_python = "rules_python",
whl_map = {
- "bar-baz": ["3.2.3", "3.1.3"],
+ "bar-baz": ["3.2", "3.1"],
},
)
@@ -154,7 +154,7 @@
The current build configuration's Python version doesn't match any of the Python
versions available for this wheel. This wheel supports the following Python versions:
- 3.1.3, 3.2.3
+ 3.1, 3.2
As matched by the `@rules_python//python/config_settings:is_python_<version>`
configuration settings.
@@ -177,8 +177,8 @@
name = "pkg",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:pkg",
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
+ "@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:pkg",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg",
},
no_match_error = _NO_MATCH_ERROR,
),
@@ -188,8 +188,8 @@
name = "whl",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:whl",
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
+ "@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:whl",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl",
},
no_match_error = _NO_MATCH_ERROR,
),
@@ -199,8 +199,8 @@
name = "data",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:data",
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
+ "@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:data",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data",
},
no_match_error = _NO_MATCH_ERROR,
),
@@ -210,8 +210,8 @@
name = "dist_info",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:dist_info",
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
+ "@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:dist_info",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info",
},
no_match_error = _NO_MATCH_ERROR,
),
@@ -224,11 +224,18 @@
def _test_bzlmod_aliases_for_non_root_modules(env):
actual = render_pkg_aliases(
- default_version = "3.2.4",
+ # NOTE @aignas 2024-01-17: if the default X.Y version coincides with the
+ # versions that are used in the root module, then this would be the same as
+ # as _test_bzlmod_aliases.
+ #
+ # However, if the root module uses a different default version than the
+ # non-root module, then we will have a no-match-error because the default_version
+ # is not in the list of the versions in the whl_map.
+ default_version = "3.3",
repo_name = "pypi",
rules_python = "rules_python",
whl_map = {
- "bar-baz": ["3.2.3", "3.1.3"],
+ "bar-baz": ["3.2", "3.1"],
},
)
@@ -241,7 +248,7 @@
The current build configuration's Python version doesn't match any of the Python
versions available for this wheel. This wheel supports the following Python versions:
- 3.1.3, 3.2.3
+ 3.1, 3.2
As matched by the `@rules_python//python/config_settings:is_python_<version>`
configuration settings.
@@ -264,8 +271,8 @@
name = "pkg",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:pkg",
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
+ "@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:pkg",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg",
},
no_match_error = _NO_MATCH_ERROR,
),
@@ -275,8 +282,8 @@
name = "whl",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:whl",
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
+ "@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:whl",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl",
},
no_match_error = _NO_MATCH_ERROR,
),
@@ -286,8 +293,8 @@
name = "data",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:data",
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
+ "@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:data",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data",
},
no_match_error = _NO_MATCH_ERROR,
),
@@ -297,8 +304,8 @@
name = "dist_info",
actual = select(
{
- "@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:dist_info",
- "@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
+ "@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:dist_info",
+ "@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info",
},
no_match_error = _NO_MATCH_ERROR,
),
@@ -311,12 +318,12 @@
def _test_bzlmod_aliases_are_created_for_all_wheels(env):
actual = render_pkg_aliases(
- default_version = "3.2.3",
+ default_version = "3.2",
repo_name = "pypi",
rules_python = "rules_python",
whl_map = {
- "bar": ["3.1.2", "3.2.3"],
- "foo": ["3.1.2", "3.2.3"],
+ "bar": ["3.1", "3.2"],
+ "foo": ["3.1", "3.2"],
},
)