diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e65ae497a..d58351a542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,9 +25,15 @@ A brief description of the categories of changes: [x.x.x]: https://github.com/bazelbuild/rules_python/releases/tag/x.x.x ### Changed -* Nothing yet +* (toolchains) `py_runtime.implementation_name` now defaults to `cpython` + (previously it defaulted to None). ### Fixed +* (bzlmod) The `python.override(minor_mapping)` now merges the default and the + overridden versions ensuring that the resultant `minor_mapping` will always + have all of the python versions. +* (bzlmod) The default value for the {obj}`--python_version` flag will now be + always set to the default python toolchain version value. * (bzlmod) correctly wire the {attr}`pip.parse.extra_pip_args` all the way to {obj}`whl_library`. What is more we will pass the `extra_pip_args` to {obj}`whl_library` for `sdist` distributions when using @@ -38,6 +44,9 @@ A brief description of the categories of changes: ### Added * (py_wheel) Now supports `compress = (True|False)` to allow disabling compression to speed up development. +* (toolchains): A public `//python/config_settings:python_version_major_minor` has + been exposed for users to be able to match on the `X.Y` version of a Python + interpreter. * (api) Added {obj}`merge_py_infos()` so user rules can merge and propagate `PyInfo` without losing information. diff --git a/WORKSPACE b/WORKSPACE index 02b3b6e926..ba05ec54c5 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -41,14 +41,14 @@ load("//:internal_setup.bzl", "rules_python_internal_setup") rules_python_internal_setup() +load("@pythons_hub//:versions.bzl", "MINOR_MAPPING", "PYTHON_VERSIONS") load("//python:repositories.bzl", "python_register_multi_toolchains") -load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS") python_register_multi_toolchains( name = "python", default_version = MINOR_MAPPING.values()[-2], # Integration tests verify each version, so register all of them. - python_versions = TOOL_VERSIONS.keys(), + python_versions = PYTHON_VERSIONS, ) load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file") diff --git a/docs/api/rules_python/python/config_settings/index.md b/docs/api/rules_python/python/config_settings/index.md index e102baaa5b..645e4e2246 100644 --- a/docs/api/rules_python/python/config_settings/index.md +++ b/docs/api/rules_python/python/config_settings/index.md @@ -10,6 +10,10 @@ Determines the default hermetic Python toolchain version. This can be set to one of the values that `rules_python` maintains. ::: +:::{bzl:target} python_version_major_minor +Parses the value of the `python_version` and transforms it into a `X.Y` value. +::: + ::::{bzl:flag} exec_tools_toolchain Determines if the {obj}`exec_tools_toolchain_type` toolchain is enabled. diff --git a/examples/bzlmod/MODULE.bazel b/examples/bzlmod/MODULE.bazel index 4ac8191051..5504172e1d 100644 --- a/examples/bzlmod/MODULE.bazel +++ b/examples/bzlmod/MODULE.bazel @@ -42,17 +42,16 @@ python.toolchain( python.override( available_python_versions = [ "3.10.9", + "3.9.18", "3.9.19", # The following is used by the `other_module` and we need to include it here # as well. "3.11.8", ], # Also override the `minor_mapping` so that the root module, - # instead of rules_python's defaults, controls what full version - # is used when `3.x` is requested. + # instead of rules_python's defaulting to the latest available version, + # controls what full version is used when `3.x` is requested. minor_mapping = { - "3.10": "3.10.9", - "3.11": "3.11.8", "3.9": "3.9.19", }, ) @@ -90,7 +89,7 @@ python.single_version_platform_override( # See the tests folder for various examples on using multiple Python versions. # The names "python_3_9" and "python_3_10" are autmatically created by the repo # rules based on the `python_version` arg values. -use_repo(python, "python_3_10", "python_3_9", "python_versions") +use_repo(python, "python_3_10", "python_3_9", "python_versions", "pythons_hub") # EXPERIMENTAL: This is experimental and may be removed without notice uv = use_extension("@rules_python//python/uv:extensions.bzl", "uv") diff --git a/examples/bzlmod/MODULE.bazel.lock b/examples/bzlmod/MODULE.bazel.lock index 604aef17c6..11e63af6e9 100644 --- a/examples/bzlmod/MODULE.bazel.lock +++ b/examples/bzlmod/MODULE.bazel.lock @@ -1231,7 +1231,7 @@ }, "@@rules_python~//python/extensions:pip.bzl%pip": { "general": { - "bzlTransitiveDigest": "W8FWi7aL0uqh7djg6csTMzkL1RB6WGRgfO/MOcbqYZI=", + "bzlTransitiveDigest": "SY5Kzq6Z7CG9q0dbCVrOHK8FFnVC6YTXBqGE4ZfNNbo=", "usagesDigest": "MChlcSw99EuW3K7OOoMcXQIdcJnEh6YmfyjJm+9mxIg=", "recordedFileInputs": { "@@other_module~//requirements_lock_3_11.txt": "a7d0061366569043d5efcf80e34a32c732679367cb3c831c4cdc606adc36d314", @@ -2955,7 +2955,6 @@ "whl_map": { "absl_py": "[{\"config_setting\":\"//_config:is_python_3.11\",\"filename\":null,\"repo\":\"other_module_pip_311_absl_py\",\"target_platforms\":null,\"version\":\"3.11\"}]" }, - "default_version": "3.9", "packages": [], "groups": {} } @@ -4267,7 +4266,6 @@ "sphinxcontrib_applehelp": "[{\"config_setting\":\"//_config:is_python_3.9\",\"filename\":\"sphinxcontrib_applehelp-1.0.7-py3-none-any.whl\",\"repo\":\"pip_39_sphinxcontrib_applehelp_py3_none_any_094c4d56\",\"target_platforms\":null,\"version\":\"3.9\"},{\"config_setting\":\"//_config:is_python_3.9\",\"filename\":\"sphinxcontrib_applehelp-1.0.7.tar.gz\",\"repo\":\"pip_39_sphinxcontrib_applehelp_sdist_39fdc8d7\",\"target_platforms\":null,\"version\":\"3.9\"},{\"config_setting\":\"//_config:is_python_3.10\",\"filename\":null,\"repo\":\"pip_310_sphinxcontrib_applehelp\",\"target_platforms\":null,\"version\":\"3.10\"}]", "sphinxcontrib_serializinghtml": "[{\"config_setting\":\"//_config:is_python_3.9\",\"filename\":\"sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl\",\"repo\":\"pip_39_sphinxcontrib_serializinghtml_py3_none_any_9b36e503\",\"target_platforms\":null,\"version\":\"3.9\"},{\"config_setting\":\"//_config:is_python_3.9\",\"filename\":\"sphinxcontrib_serializinghtml-1.1.9.tar.gz\",\"repo\":\"pip_39_sphinxcontrib_serializinghtml_sdist_0c64ff89\",\"target_platforms\":null,\"version\":\"3.9\"},{\"config_setting\":\"//_config:is_python_3.10\",\"filename\":null,\"repo\":\"pip_310_sphinxcontrib_serializinghtml\",\"target_platforms\":null,\"version\":\"3.10\"}]" }, - "default_version": "3.9", "packages": [ "alabaster", "astroid", @@ -6140,7 +6138,7 @@ }, "@@rules_python~//python/private/pypi:pip.bzl%pip_internal": { "general": { - "bzlTransitiveDigest": "9aEp4XU4yVL6sJqODxio5iSCoqf37Ro3o+Mt1izDnq8=", + "bzlTransitiveDigest": "BLXk2JiegzzGfis5XuIaAVMg5WUUhmsofn99NgeBDEQ=", "usagesDigest": "Y8ihY+R57BAFhalrVLVdJFrpwlbsiKz9JPJ99ljF7HA=", "recordedFileInputs": { "@@rules_python~//tools/publish/requirements.txt": "031e35d03dde03ae6305fe4b3d1f58ad7bdad857379752deede0f93649991b8a", @@ -8105,7 +8103,6 @@ "importlib_metadata": "[{\"config_setting\":\"//_config:is_python_3.11\",\"filename\":\"importlib_metadata-6.0.0-py3-none-any.whl\",\"repo\":\"rules_python_publish_deps_311_importlib_metadata_py3_none_any_7efb448e\",\"target_platforms\":null,\"version\":\"3.11\"},{\"config_setting\":\"//_config:is_python_3.11\",\"filename\":\"importlib_metadata-6.0.0.tar.gz\",\"repo\":\"rules_python_publish_deps_311_importlib_metadata_sdist_e354bede\",\"target_platforms\":null,\"version\":\"3.11\"}]", "pywin32_ctypes": "[{\"config_setting\":\"//_config:is_python_3.11\",\"filename\":\"pywin32_ctypes-0.2.0-py2.py3-none-any.whl\",\"repo\":\"rules_python_publish_deps_311_pywin32_ctypes_py2_none_any_9dc2d991\",\"target_platforms\":null,\"version\":\"3.11\"},{\"config_setting\":\"//_config:is_python_3.11\",\"filename\":\"pywin32-ctypes-0.2.0.tar.gz\",\"repo\":\"rules_python_publish_deps_311_pywin32_ctypes_sdist_24ffc3b3\",\"target_platforms\":null,\"version\":\"3.11\"}]" }, - "default_version": "3.9", "packages": [ "bleach", "certifi", diff --git a/examples/bzlmod/tests/BUILD.bazel b/examples/bzlmod/tests/BUILD.bazel index 9f7aa1ba00..a778ca1aee 100644 --- a/examples/bzlmod/tests/BUILD.bazel +++ b/examples/bzlmod/tests/BUILD.bazel @@ -1,8 +1,8 @@ load("@python_versions//3.10:defs.bzl", py_binary_3_10 = "py_binary", py_test_3_10 = "py_test") load("@python_versions//3.11:defs.bzl", py_binary_3_11 = "py_binary", py_test_3_11 = "py_test") load("@python_versions//3.9:defs.bzl", py_binary_3_9 = "py_binary", py_test_3_9 = "py_test") +load("@pythons_hub//:versions.bzl", "MINOR_MAPPING") load("@rules_python//python:defs.bzl", "py_binary", "py_test") -load("@rules_python//python:versions.bzl", "MINOR_MAPPING") load("@rules_python//python/config_settings:transition.bzl", py_versioned_binary = "py_binary", py_versioned_test = "py_test") py_binary( diff --git a/internal_setup.bzl b/internal_setup.bzl index 1967c0e568..3029c1546f 100644 --- a/internal_setup.bzl +++ b/internal_setup.bzl @@ -22,13 +22,25 @@ load("@rules_bazel_integration_test//bazel_integration_test:deps.bzl", "bazel_in load("@rules_bazel_integration_test//bazel_integration_test:repo_defs.bzl", "bazel_binaries") load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") load("//:version.bzl", "SUPPORTED_BAZEL_VERSIONS") +load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS") load("//python/private:internal_config_repo.bzl", "internal_config_repo") # buildifier: disable=bzl-visibility +load("//python/private:pythons_hub.bzl", "hub_repo") # buildifier: disable=bzl-visibility load("//python/private/pypi:deps.bzl", "pypi_deps") # buildifier: disable=bzl-visibility def rules_python_internal_setup(): """Setup for rules_python tests and tools.""" internal_config_repo(name = "rules_python_internal") + hub_repo( + name = "pythons_hub", + minor_mapping = MINOR_MAPPING, + default_python_version = "", + toolchain_prefixes = [], + toolchain_python_versions = [], + toolchain_set_python_version_constraints = [], + toolchain_user_repository_names = [], + python_versions = sorted(TOOL_VERSIONS.keys()), + ) # Because we don't use the pip_install rule, we have to call this to fetch its deps pypi_deps() diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index c31d69f202..9fb395741b 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -1,5 +1,5 @@ load("@bazel_skylib//rules:common_settings.bzl", "string_flag") -load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS") +load("@pythons_hub//:versions.bzl", "DEFAULT_PYTHON_VERSION", "MINOR_MAPPING", "PYTHON_VERSIONS") load( "//python/private:flags.bzl", "BootstrapImplFlag", @@ -28,8 +28,9 @@ filegroup( construct_config_settings( name = "construct_config_settings", + default_version = DEFAULT_PYTHON_VERSION, minor_mapping = MINOR_MAPPING, - versions = TOOL_VERSIONS.keys(), + versions = PYTHON_VERSIONS, ) string_flag( diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel index f128742b2c..cb0fd5ca02 100644 --- a/python/private/BUILD.bazel +++ b/python/private/BUILD.bazel @@ -165,6 +165,8 @@ bzl_library( deps = [ ":bazel_tools_bzl", ":internal_config_repo_bzl", + ":pythons_hub_bzl", + "//python:versions_bzl", "//python/private/pypi:deps_bzl", ], ) @@ -212,6 +214,7 @@ bzl_library( srcs = ["pythons_hub.bzl"], deps = [ ":py_toolchain_suite_bzl", + ":text_util_bzl", ], ) diff --git a/python/private/common/py_runtime_rule.bzl b/python/private/common/py_runtime_rule.bzl index b339425099..d944796118 100644 --- a/python/private/common/py_runtime_rule.bzl +++ b/python/private/common/py_runtime_rule.bzl @@ -226,6 +226,7 @@ runtime. For a platform runtime this attribute must not be set. ), "implementation_name": attr.string( doc = "The Python implementation name (`sys.implementation.name`)", + default = "cpython", ), "interpreter": attr.label( # We set `allow_files = True` to allow specifying executable diff --git a/python/private/config_settings.bzl b/python/private/config_settings.bzl index b15d6a8e03..10b4d686a7 100644 --- a/python/private/config_settings.bzl +++ b/python/private/config_settings.bzl @@ -20,9 +20,9 @@ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load(":semver.bzl", "semver") _PYTHON_VERSION_FLAG = Label("//python/config_settings:python_version") -_PYTHON_VERSION_MAJOR_MINOR_FLAG = Label("//python/config_settings:_python_version_major_minor") +_PYTHON_VERSION_MAJOR_MINOR_FLAG = Label("//python/config_settings:python_version_major_minor") -def construct_config_settings(*, name, versions, minor_mapping): # buildifier: disable=function-docstring +def construct_config_settings(*, name, default_version, versions, minor_mapping): # buildifier: disable=function-docstring """Create a 'python_version' config flag and construct all config settings used in rules_python. This mainly includes the targets that are used in the toolchain and pip hub @@ -30,17 +30,14 @@ def construct_config_settings(*, name, versions, minor_mapping): # buildifier: Args: name: {type}`str` A dummy name value that is no-op for now. + default_version: {type}`str` the default value for the `python_version` flag. versions: {type}`list[str]` A list of versions to build constraint settings for. minor_mapping: {type}`dict[str, str]` A mapping from `X.Y` to `X.Y.Z` python versions. """ _ = name # @unused _python_version_flag( name = _PYTHON_VERSION_FLAG.name, - # 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 = "", + build_setting_default = default_version, visibility = ["//visibility:public"], ) diff --git a/python/private/py_repositories.bzl b/python/private/py_repositories.bzl index 8ddcb5d3a7..ff8a6389ba 100644 --- a/python/private/py_repositories.bzl +++ b/python/private/py_repositories.bzl @@ -16,8 +16,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS") load("//python/private/pypi:deps.bzl", "pypi_deps") load(":internal_config_repo.bzl", "internal_config_repo") +load(":pythons_hub.bzl", "hub_repo") def http_archive(**kwargs): maybe(_http_archive, **kwargs) @@ -32,6 +34,17 @@ def py_repositories(): internal_config_repo, name = "rules_python_internal", ) + maybe( + hub_repo, + name = "pythons_hub", + minor_mapping = MINOR_MAPPING, + default_python_version = "", + toolchain_prefixes = [], + toolchain_python_versions = [], + toolchain_set_python_version_constraints = [], + toolchain_user_repository_names = [], + python_versions = sorted(TOOL_VERSIONS.keys()), + ) http_archive( name = "bazel_skylib", sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506", diff --git a/python/private/pypi/BUILD.bazel b/python/private/pypi/BUILD.bazel index 8cfd3d6525..e76f9d36b1 100644 --- a/python/private/pypi/BUILD.bazel +++ b/python/private/pypi/BUILD.bazel @@ -13,7 +13,6 @@ # limitations under the License. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") package(default_visibility = ["//:__subpackages__"]) @@ -59,9 +58,9 @@ bzl_library( srcs = ["extension.bzl"], deps = [ ":attrs_bzl", + ":evaluate_markers_bzl", ":hub_repository_bzl", ":parse_requirements_bzl", - ":evaluate_markers_bzl", ":parse_whl_name_bzl", ":pip_repository_attrs_bzl", ":simpleapi_download_bzl", @@ -69,12 +68,11 @@ bzl_library( ":whl_repo_name_bzl", "//python/private:full_version_bzl", "//python/private:normalize_name_bzl", - "//python/private:version_label_bzl", "//python/private:semver_bzl", + "//python/private:version_label_bzl", "@bazel_features//:features", - ] + [ "@pythons_hub//:interpreters_bzl", - ] if BZLMOD_ENABLED else [], + ], ) bzl_library( diff --git a/python/private/pypi/config_settings.bzl b/python/private/pypi/config_settings.bzl index 974121782f..492acf1895 100644 --- a/python/private/pypi/config_settings.bzl +++ b/python/private/pypi/config_settings.bzl @@ -109,9 +109,15 @@ def config_settings( for python_version in [""] + python_versions: is_python = "is_python_{}".format(python_version or "version_unset") - native.alias( + + # The aliases defined in @rules_python//python/config_settings may not + # have config settings for the versions we need, so define our own + # config settings instead. + native.config_setting( name = is_python, - actual = Label("//python/config_settings:" + is_python), + flag_values = { + Label("//python/config_settings:python_version_major_minor"): python_version, + }, visibility = visibility, ) diff --git a/python/private/pypi/extension.bzl b/python/private/pypi/extension.bzl index 712d2fefda..200aa4327e 100644 --- a/python/private/pypi/extension.bzl +++ b/python/private/pypi/extension.bzl @@ -15,7 +15,7 @@ "pip module extension for use with bzlmod" load("@bazel_features//:features.bzl", "bazel_features") -load("@pythons_hub//:interpreters.bzl", "DEFAULT_PYTHON_VERSION", "INTERPRETER_LABELS") +load("@pythons_hub//:interpreters.bzl", "INTERPRETER_LABELS") load("//python/private:auth.bzl", "AUTH_ATTRS") load("//python/private:normalize_name.bzl", "normalize_name") load("//python/private:repo_utils.bzl", "repo_utils") @@ -506,7 +506,6 @@ def _pip_impl(module_ctx): key: json.encode(value) for key, value in whl_map.items() }, - default_version = _major_minor_version(DEFAULT_PYTHON_VERSION), packages = sorted(exposed_packages.get(hub_name, {})), groups = hub_group_map.get(hub_name), ) diff --git a/python/private/pypi/generate_whl_library_build_bazel.bzl b/python/private/pypi/generate_whl_library_build_bazel.bzl index 0be6f9c409..934fa00c69 100644 --- a/python/private/pypi/generate_whl_library_build_bazel.bzl +++ b/python/private/pypi/generate_whl_library_build_bazel.bzl @@ -162,7 +162,7 @@ def _render_config_settings(dependencies_by_platform): config_setting( name = "is_{name}", flag_values = {{ - "@rules_python//python/config_settings:_python_version_major_minor": "3.{minor_version}", + "@rules_python//python/config_settings:python_version_major_minor": "3.{minor_version}", }}, constraint_values = {constraint_values}, visibility = ["//visibility:private"], diff --git a/python/private/pypi/hub_repository.bzl b/python/private/pypi/hub_repository.bzl index f589dd4744..7afb616e3d 100644 --- a/python/private/pypi/hub_repository.bzl +++ b/python/private/pypi/hub_repository.bzl @@ -35,8 +35,6 @@ def _impl(rctx): key: [whl_alias(**v) for v in json.decode(values)] for key, values in rctx.attr.whl_map.items() }, - default_version = rctx.attr.default_version, - default_config_setting = "//_config:is_python_" + rctx.attr.default_version, requirement_cycles = rctx.attr.groups, ) for path, contents in aliases.items(): @@ -67,13 +65,6 @@ def _impl(rctx): hub_repository = repository_rule( attrs = { - "default_version": attr.string( - mandatory = True, - doc = """\ -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.""", - ), "groups": attr.string_list_dict( mandatory = False, ), diff --git a/python/private/pypi/render_pkg_aliases.bzl b/python/private/pypi/render_pkg_aliases.bzl index 9e5158f8f0..0086bfff8f 100644 --- a/python/private/pypi/render_pkg_aliases.bzl +++ b/python/private/pypi/render_pkg_aliases.bzl @@ -73,7 +73,6 @@ which has a "null" version value and will not match version constraints. def _render_whl_library_alias( *, name, - default_config_setting, aliases, target_name, **kwargs): @@ -97,9 +96,6 @@ def _render_whl_library_alias( for alias in sorted(aliases, key = lambda x: x.version): actual = "@{repo}//:{name}".format(repo = alias.repo, name = target_name) selects.setdefault(actual, []).append(alias.config_setting) - if alias.config_setting == default_config_setting: - selects[actual].append("//conditions:default") - no_match_error = None return render.alias( name = name, @@ -121,7 +117,7 @@ def _render_whl_library_alias( **kwargs ) -def _render_common_aliases(*, name, aliases, default_config_setting = None, group_name = None): +def _render_common_aliases(*, name, aliases, group_name = None): lines = [ """load("@bazel_skylib//lib:selects.bzl", "selects")""", """package(default_visibility = ["//visibility:public"])""", @@ -131,9 +127,7 @@ def _render_common_aliases(*, name, aliases, default_config_setting = None, grou if aliases: config_settings = sorted([v.config_setting for v in aliases if v.config_setting]) - if not config_settings or default_config_setting in config_settings: - pass - else: + if config_settings: error_msg = NO_MATCH_ERROR_MESSAGE_TEMPLATE_V2.format( config_settings = render.indent( "\n".join(config_settings), @@ -145,10 +139,6 @@ def _render_common_aliases(*, name, aliases, default_config_setting = None, grou error_msg = error_msg, )) - # This is to simplify the code in _render_whl_library_alias and to ensure - # that we don't pass a 'default_version' that is not in 'versions'. - default_config_setting = None - lines.append( render.alias( name = name, @@ -159,7 +149,6 @@ def _render_common_aliases(*, name, aliases, default_config_setting = None, grou [ _render_whl_library_alias( name = name, - default_config_setting = default_config_setting, aliases = aliases, target_name = target_name, visibility = ["//_groups:__subpackages__"] if name.startswith("_") else None, @@ -188,7 +177,7 @@ def _render_common_aliases(*, name, aliases, default_config_setting = None, grou return "\n\n".join(lines) -def render_pkg_aliases(*, aliases, default_config_setting = None, requirement_cycles = None): +def render_pkg_aliases(*, aliases, requirement_cycles = None): """Create alias declarations for each PyPI package. The aliases should be appended to the pip_repository BUILD.bazel file. These aliases @@ -198,7 +187,6 @@ def render_pkg_aliases(*, aliases, default_config_setting = None, requirement_cy Args: aliases: dict, the keys are normalized distribution names and values are the whl_alias instances. - default_config_setting: the default to be used for the aliases. requirement_cycles: any package groups to also add. Returns: @@ -227,7 +215,6 @@ def render_pkg_aliases(*, aliases, default_config_setting = None, requirement_cy "{}/BUILD.bazel".format(normalize_name(name)): _render_common_aliases( name = normalize_name(name), aliases = pkg_aliases, - default_config_setting = default_config_setting, group_name = whl_group_mapping.get(normalize_name(name)), ).strip() for name, pkg_aliases in aliases.items() @@ -278,13 +265,12 @@ def whl_alias(*, repo, version = None, config_setting = None, filename = None, t target_platforms = target_platforms, ) -def render_multiplatform_pkg_aliases(*, aliases, default_version = None, **kwargs): +def render_multiplatform_pkg_aliases(*, aliases, **kwargs): """Render the multi-platform pkg aliases. Args: aliases: dict[str, list(whl_alias)] A list of aliases that will be transformed from ones having `filename` to ones having `config_setting`. - default_version: str, the default python version. Defaults to None. **kwargs: extra arguments passed to render_pkg_aliases. Returns: @@ -302,7 +288,6 @@ def render_multiplatform_pkg_aliases(*, aliases, default_version = None, **kwarg config_setting_aliases = { pkg: multiplatform_whl_aliases( aliases = pkg_aliases, - default_version = default_version, glibc_versions = flag_versions.get("glibc_versions", []), muslc_versions = flag_versions.get("muslc_versions", []), osx_versions = flag_versions.get("osx_versions", []), @@ -317,14 +302,13 @@ def render_multiplatform_pkg_aliases(*, aliases, default_version = None, **kwarg contents["_config/BUILD.bazel"] = _render_config_settings(**flag_versions) return contents -def multiplatform_whl_aliases(*, aliases, default_version = None, **kwargs): +def multiplatform_whl_aliases(*, aliases, **kwargs): """convert a list of aliases from filename to config_setting ones. Args: aliases: list(whl_alias): The aliases to process. Any aliases that have the filename set will be converted to a list of aliases, each with an appropriate config_setting value. - default_version: string | None, the default python version to use. **kwargs: Extra parameters passed to get_filename_config_settings. Returns: @@ -344,7 +328,6 @@ def multiplatform_whl_aliases(*, aliases, default_version = None, **kwargs): filename = alias.filename, target_platforms = alias.target_platforms, python_version = alias.version, - python_default = default_version == alias.version, **kwargs ) @@ -511,8 +494,7 @@ def get_filename_config_settings( glibc_versions, muslc_versions, osx_versions, - python_version = "", - python_default = True): + python_version): """Get the filename config settings. Args: @@ -522,7 +504,6 @@ def get_filename_config_settings( muslc_versions: list[tuple[int, int]], list of versions. osx_versions: list[tuple[int, int]], list of versions. python_version: the python version to generate the config_settings for. - python_default: if we should include the setting when python_version is not set. Returns: A tuple: @@ -573,18 +554,9 @@ def get_filename_config_settings( prefixes = ["sdist"] suffixes = [_non_versioned_platform(p) for p in target_platforms or []] - if python_default and python_version: - prefixes += ["cp{}_{}".format(python_version, p) for p in prefixes] - elif python_version: - prefixes = ["cp{}_{}".format(python_version, p) for p in prefixes] - elif python_default: - pass - else: - fail("BUG: got no python_version and it is not default") - versioned = { - ":is_{}_{}".format(p, suffix): { - version: ":is_{}_{}".format(p, setting) + ":is_cp{}_{}_{}".format(python_version, p, suffix): { + version: ":is_cp{}_{}_{}".format(python_version, p, setting) for version, setting in versions.items() } for p in prefixes @@ -592,9 +564,9 @@ def get_filename_config_settings( } if suffixes or versioned: - return [":is_{}_{}".format(p, s) for p in prefixes for s in suffixes], versioned + return [":is_cp{}_{}_{}".format(python_version, p, s) for p in prefixes for s in suffixes], versioned else: - return [":is_{}".format(p) for p in prefixes], setting_supported_versions + return [":is_cp{}_{}".format(python_version, p) for p in prefixes], setting_supported_versions def _whl_config_setting_suffixes( platform_tag, diff --git a/python/private/python.bzl b/python/private/python.bzl index cedf39a5c7..83bc43f92e 100644 --- a/python/private/python.bzl +++ b/python/private/python.bzl @@ -236,6 +236,7 @@ def _python_impl(module_ctx): name = "pythons_hub", # Last toolchain is default default_python_version = py.default_python_version, + minor_mapping = py.config.minor_mapping, toolchain_prefixes = [ render.toolchain_prefix(index, toolchain.name, _TOOLCHAIN_INDEX_PAD_LENGTH) for index, toolchain in enumerate(py.toolchains) @@ -493,20 +494,23 @@ def _get_toolchain_config(*, modules, _fail = fail): _fail = _fail, ) - minor_mapping = default.pop("minor_mapping", {}) register_all_versions = default.pop("register_all_versions", False) kwargs = default.pop("kwargs", {}) - if not minor_mapping: - versions = {} - for version_string in available_versions: - v = semver(version_string) - versions.setdefault("{}.{}".format(v.major, v.minor), []).append((int(v.patch), version_string)) + versions = {} + for version_string in available_versions: + v = semver(version_string) + versions.setdefault("{}.{}".format(v.major, v.minor), []).append((int(v.patch), version_string)) - minor_mapping = { - major_minor: max(subset)[1] - for major_minor, subset in versions.items() - } + minor_mapping = { + major_minor: max(subset)[1] + for major_minor, subset in versions.items() + } + + # The following ensures that all of the versions will be present in the minor_mapping + minor_mapping_overrides = default.pop("minor_mapping", {}) + for major_minor, full in minor_mapping_overrides.items(): + minor_mapping[major_minor] = full return struct( kwargs = kwargs, @@ -705,6 +709,10 @@ and `3.11.4` then the default for the `minor_mapping` dict will be: "3.11": "3.11.4", } ``` + +:::{versionchanged} 0.37.0 +The values in this mapping override the default values and do not replace them. +::: """, default = {}, ), diff --git a/python/private/python_register_multi_toolchains.bzl b/python/private/python_register_multi_toolchains.bzl index 68f5249350..1c7138d0e9 100644 --- a/python/private/python_register_multi_toolchains.bzl +++ b/python/private/python_register_multi_toolchains.bzl @@ -15,6 +15,10 @@ """This file contains repository rules and macros to support toolchain registration. """ +# NOTE @aignas 2024-10-07: we are not importing this from `@pythons_hub` because of this +# leading to a backwards incompatible change - the `//python:repositories.bzl` is loading +# from this file and it will cause a circular import loop and an error. If the users in +# WORKSPACE world want to override the `minor_mapping`, they will have to pass an argument. load("//python:versions.bzl", "MINOR_MAPPING") load(":python_register_toolchains.bzl", "python_register_toolchains") load(":toolchains_repo.bzl", "multi_toolchain_aliases") diff --git a/python/private/pythons_hub.bzl b/python/private/pythons_hub.bzl index da6c80d078..fdaad60e22 100644 --- a/python/private/pythons_hub.bzl +++ b/python/private/pythons_hub.bzl @@ -14,10 +14,8 @@ "Repo rule used by bzlmod extension to create a repo that has a map of Python interpreters and their labels" -load( - "//python/private:toolchains_repo.bzl", - "python_toolchain_build_file_content", -) +load(":text_util.bzl", "render") +load(":toolchains_repo.bzl", "python_toolchain_build_file_content") def _have_same_length(*lists): if not lists: @@ -34,6 +32,12 @@ bzl_library( visibility = ["@rules_python//:__subpackages__"], ) +bzl_library( + name = "versions_bzl", + srcs = ["versions.bzl"], + visibility = ["@rules_python//:__subpackages__"], +) + {toolchains} """ @@ -82,6 +86,12 @@ _line_for_hub_template = """\ "{name}_host": Label("@{name}_host//:python"), """ +_versions_bzl_template = """ +DEFAULT_PYTHON_VERSION = "{default_python_version}" +MINOR_MAPPING = {minor_mapping} +PYTHON_VERSIONS = {python_versions} +""" + def _hub_repo_impl(rctx): # Create the various toolchain definitions and # write them to the BUILD file. @@ -107,8 +117,22 @@ def _hub_repo_impl(rctx): rctx.file( "interpreters.bzl", _interpreters_bzl_template.format( + # TODO @aignas 2024-09-28: before 1.0 remove the value from here + default_python_version = rctx.attr.default_python_version, interpreter_labels = interpreter_labels, + ), + executable = False, + ) + + rctx.file( + "versions.bzl", + _versions_bzl_template.format( default_python_version = rctx.attr.default_python_version, + minor_mapping = render.dict(rctx.attr.minor_mapping), + python_versions = rctx.attr.python_versions or render.list(sorted({ + v: None + for v in rctx.attr.toolchain_python_versions + })), ), executable = False, ) @@ -125,6 +149,14 @@ This rule also writes out the various toolchains for the different Python versio doc = "Default Python version for the build in `X.Y` or `X.Y.Z` format.", mandatory = True, ), + "minor_mapping": attr.string_dict( + doc = "The minor mapping of the `X.Y` to `X.Y.Z` format that is used in config settings.", + mandatory = True, + ), + "python_versions": attr.string_list( + doc = "The list of python versions to include in the `interpreters.bzl` if the toolchains are not specified. Used in `WORKSPACE` builds.", + mandatory = False, + ), "toolchain_prefixes": attr.string_list( doc = "List prefixed for the toolchains", mandatory = True, diff --git a/tests/config_settings/construct_config_settings_tests.bzl b/tests/config_settings/construct_config_settings_tests.bzl index 9e6b6e1fc3..087efbbc70 100644 --- a/tests/config_settings/construct_config_settings_tests.bzl +++ b/tests/config_settings/construct_config_settings_tests.bzl @@ -13,7 +13,7 @@ # limitations under the License. """Tests for construction of Python version matching config settings.""" -load("@//python:versions.bzl", "MINOR_MAPPING") +load("@pythons_hub//:versions.bzl", "MINOR_MAPPING") load("@rules_testing//lib:analysis_test.bzl", "analysis_test") load("@rules_testing//lib:test_suite.bzl", "test_suite") load("@rules_testing//lib:truth.bzl", "subjects") @@ -167,7 +167,7 @@ def construct_config_settings_test_suite(name): # buildifier: disable=function- "@platforms//os:" + os, ], flag_values = { - "//python/config_settings:_python_version_major_minor": "3.11", + "//python/config_settings:python_version_major_minor": "3.11", }, ) @@ -178,7 +178,7 @@ def construct_config_settings_test_suite(name): # buildifier: disable=function- "@platforms//cpu:" + cpu, ], flag_values = { - "//python/config_settings:_python_version_major_minor": "3.11", + "//python/config_settings:python_version_major_minor": "3.11", }, ) @@ -198,7 +198,7 @@ def construct_config_settings_test_suite(name): # buildifier: disable=function- "@platforms//os:" + os, ], flag_values = { - "//python/config_settings:_python_version_major_minor": "3.11", + "//python/config_settings:python_version_major_minor": "3.11", }, ) diff --git a/tests/pypi/config_settings/config_settings_tests.bzl b/tests/pypi/config_settings/config_settings_tests.bzl index 87e18b412f..a77fa5b66b 100644 --- a/tests/pypi/config_settings/config_settings_tests.bzl +++ b/tests/pypi/config_settings/config_settings_tests.bzl @@ -55,6 +55,8 @@ def _analysis_test(*, name, dist, want, config_settings = [_flag.platform("linux config_settings = dict(config_settings) if not config_settings: fail("For reproducibility on different platforms, the config setting must be specified") + python_version, default_value = _flag.python_version("3.7.10") + config_settings.setdefault(python_version, default_value) analysis_test( name = name, @@ -75,7 +77,7 @@ def _test_sdist_default(name): _analysis_test( name = name, dist = { - "is_sdist": "sdist", + "is_cp3.7_sdist": "sdist", }, want = "sdist", ) @@ -86,7 +88,7 @@ def _test_sdist_no_whl(name): _analysis_test( name = name, dist = { - "is_sdist": "sdist", + "is_cp3.7_sdist": "sdist", }, config_settings = [ _flag.platform("linux_aarch64"), @@ -101,7 +103,7 @@ def _test_sdist_no_sdist(name): _analysis_test( name = name, dist = { - "is_sdist": "sdist", + "is_cp3.7_sdist": "sdist", }, config_settings = [ _flag.platform("linux_aarch64"), @@ -118,8 +120,8 @@ def _test_basic_whl_default(name): _analysis_test( name = name, dist = { - "is_py_none_any": "whl", - "is_sdist": "sdist", + "is_cp3.7_py_none_any": "whl", + "is_cp3.7_sdist": "sdist", }, want = "whl", ) @@ -130,8 +132,8 @@ def _test_basic_whl_nowhl(name): _analysis_test( name = name, dist = { - "is_py_none_any": "whl", - "is_sdist": "sdist", + "is_cp3.7_py_none_any": "whl", + "is_cp3.7_sdist": "sdist", }, config_settings = [ _flag.platform("linux_aarch64"), @@ -146,8 +148,8 @@ def _test_basic_whl_nosdist(name): _analysis_test( name = name, dist = { - "is_py_none_any": "whl", - "is_sdist": "sdist", + "is_cp3.7_py_none_any": "whl", + "is_cp3.7_sdist": "sdist", }, config_settings = [ _flag.platform("linux_aarch64"), @@ -162,8 +164,8 @@ def _test_whl_default(name): _analysis_test( name = name, dist = { - "is_py3_none_any": "whl", - "is_py_none_any": "basic_whl", + "is_cp3.7_py3_none_any": "whl", + "is_cp3.7_py_none_any": "basic_whl", }, want = "whl", ) @@ -174,8 +176,8 @@ def _test_whl_nowhl(name): _analysis_test( name = name, dist = { - "is_py3_none_any": "whl", - "is_py_none_any": "basic_whl", + "is_cp3.7_py3_none_any": "whl", + "is_cp3.7_py_none_any": "basic_whl", }, config_settings = [ _flag.platform("linux_aarch64"), @@ -190,7 +192,7 @@ def _test_whl_nosdist(name): _analysis_test( name = name, dist = { - "is_py3_none_any": "whl", + "is_cp3.7_py3_none_any": "whl", }, config_settings = [ _flag.platform("linux_aarch64"), @@ -205,8 +207,8 @@ def _test_abi_whl_is_prefered(name): _analysis_test( name = name, dist = { - "is_py3_abi3_any": "abi_whl", - "is_py3_none_any": "whl", + "is_cp3.7_py3_abi3_any": "abi_whl", + "is_cp3.7_py3_none_any": "whl", }, want = "abi_whl", ) @@ -217,9 +219,9 @@ def _test_whl_with_constraints_is_prefered(name): _analysis_test( name = name, dist = { - "is_py3_none_any": "default_whl", - "is_py3_none_any_linux_aarch64": "whl", - "is_py3_none_any_linux_x86_64": "amd64_whl", + "is_cp3.7_py3_none_any": "default_whl", + "is_cp3.7_py3_none_any_linux_aarch64": "whl", + "is_cp3.7_py3_none_any_linux_x86_64": "amd64_whl", }, want = "whl", ) @@ -230,9 +232,9 @@ def _test_cp_whl_is_prefered_over_py3(name): _analysis_test( name = name, dist = { - "is_cp3x_none_any": "cp", - "is_py3_abi3_any": "py3_abi3", - "is_py3_none_any": "py3", + "is_cp3.7_cp3x_none_any": "cp", + "is_cp3.7_py3_abi3_any": "py3_abi3", + "is_cp3.7_py3_none_any": "py3", }, want = "cp", ) @@ -243,8 +245,8 @@ def _test_cp_abi_whl_is_prefered_over_py3(name): _analysis_test( name = name, dist = { - "is_cp3x_abi3_any": "cp", - "is_py3_abi3_any": "py3", + "is_cp3.7_cp3x_abi3_any": "cp", + "is_cp3.7_py3_abi3_any": "py3", }, want = "cp", ) @@ -258,7 +260,6 @@ def _test_cp_version_is_selected_when_python_version_is_specified(name): "is_cp3.10_cp3x_none_any": "cp310", "is_cp3.8_cp3x_none_any": "cp38", "is_cp3.9_cp3x_none_any": "cp39", - "is_cp3x_none_any": "cp_default", }, want = "cp310", config_settings = [ @@ -319,11 +320,11 @@ def _test_platform_whl_is_prefered_over_any_whl_with_constraints(name): _analysis_test( name = name, dist = { - "is_py3_abi3_any": "better_default_whl", - "is_py3_abi3_any_linux_aarch64": "better_default_any_whl", - "is_py3_none_any": "default_whl", - "is_py3_none_any_linux_aarch64": "whl", - "is_py3_none_linux_aarch64": "platform_whl", + "is_cp3.7_py3_abi3_any": "better_default_whl", + "is_cp3.7_py3_abi3_any_linux_aarch64": "better_default_any_whl", + "is_cp3.7_py3_none_any": "default_whl", + "is_cp3.7_py3_none_any_linux_aarch64": "whl", + "is_cp3.7_py3_none_linux_aarch64": "platform_whl", }, want = "platform_whl", ) @@ -334,8 +335,8 @@ def _test_abi3_platform_whl_preference(name): _analysis_test( name = name, dist = { - "is_py3_abi3_linux_aarch64": "abi3_platform", - "is_py3_none_linux_aarch64": "platform", + "is_cp3.7_py3_abi3_linux_aarch64": "abi3_platform", + "is_cp3.7_py3_none_linux_aarch64": "platform", }, want = "abi3_platform", ) @@ -346,8 +347,8 @@ def _test_glibc(name): _analysis_test( name = name, dist = { - "is_cp3x_cp_manylinux_aarch64": "glibc", - "is_py3_abi3_linux_aarch64": "abi3_platform", + "is_cp3.7_cp3x_cp_manylinux_aarch64": "glibc", + "is_cp3.7_py3_abi3_linux_aarch64": "abi3_platform", }, want = "glibc", ) @@ -358,9 +359,9 @@ def _test_glibc_versioned(name): _analysis_test( name = name, dist = { - "is_cp3x_cp_manylinux_2_14_aarch64": "glibc", - "is_cp3x_cp_manylinux_2_17_aarch64": "glibc", - "is_py3_abi3_linux_aarch64": "abi3_platform", + "is_cp3.7_cp3x_cp_manylinux_2_14_aarch64": "glibc", + "is_cp3.7_cp3x_cp_manylinux_2_17_aarch64": "glibc", + "is_cp3.7_py3_abi3_linux_aarch64": "abi3_platform", }, want = "glibc", config_settings = [ @@ -378,8 +379,8 @@ def _test_glibc_compatible_exists(name): dist = { # Code using the conditions will need to construct selects, which # do the version matching correctly. - "is_cp3x_cp_manylinux_2_14_aarch64": "2_14_whl_via_2_14_branch", - "is_cp3x_cp_manylinux_2_17_aarch64": "2_14_whl_via_2_17_branch", + "is_cp3.7_cp3x_cp_manylinux_2_14_aarch64": "2_14_whl_via_2_14_branch", + "is_cp3.7_cp3x_cp_manylinux_2_17_aarch64": "2_14_whl_via_2_17_branch", }, want = "2_14_whl_via_2_17_branch", config_settings = [ @@ -395,7 +396,7 @@ def _test_musl(name): _analysis_test( name = name, dist = { - "is_cp3x_cp_musllinux_aarch64": "musl", + "is_cp3.7_cp3x_cp_musllinux_aarch64": "musl", }, want = "musl", config_settings = [ @@ -410,7 +411,7 @@ def _test_windows(name): _analysis_test( name = name, dist = { - "is_cp3x_cp_windows_x86_64": "whl", + "is_cp3.7_cp3x_cp_windows_x86_64": "whl", }, want = "whl", config_settings = [ @@ -425,8 +426,8 @@ def _test_osx(name): name = name, dist = { # We prefer arch specific whls over universal - "is_cp3x_cp_osx_x86_64": "whl", - "is_cp3x_cp_osx_x86_64_universal2": "universal_whl", + "is_cp3.7_cp3x_cp_osx_x86_64": "whl", + "is_cp3.7_cp3x_cp_osx_x86_64_universal2": "universal_whl", }, want = "whl", config_settings = [ @@ -441,7 +442,7 @@ def _test_osx_universal_default(name): name = name, dist = { # We default to universal if only that exists - "is_cp3x_cp_osx_x86_64_universal2": "whl", + "is_cp3.7_cp3x_cp_osx_x86_64_universal2": "whl", }, want = "whl", config_settings = [ @@ -456,8 +457,8 @@ def _test_osx_universal_only(name): name = name, dist = { # If we prefer universal, then we use that - "is_cp3x_cp_osx_x86_64": "whl", - "is_cp3x_cp_osx_x86_64_universal2": "universal", + "is_cp3.7_cp3x_cp_osx_x86_64": "whl", + "is_cp3.7_cp3x_cp_osx_x86_64_universal2": "universal", }, want = "universal", config_settings = [ @@ -474,7 +475,7 @@ def _test_osx_os_version(name): dist = { # Similarly to the libc version, the user of the config settings will have to # construct the select so that the version selection is correct. - "is_cp3x_cp_osx_10_9_x86_64": "whl", + "is_cp3.7_cp3x_cp_osx_10_9_x86_64": "whl", }, want = "whl", config_settings = [ @@ -489,7 +490,7 @@ def _test_all(name): _analysis_test( name = name, dist = { - "is_" + f: f + "is_cp3.7_" + f: f for f in [ "{py}_{abi}_{plat}".format(py = valid_py, abi = valid_abi, plat = valid_plat) # we have py2.py3, py3, cp3x @@ -528,7 +529,7 @@ def config_settings_test_suite(name): # buildifier: disable=function-docstring config_settings( name = "dummy", - python_versions = ["3.8", "3.9", "3.10"], + python_versions = ["3.7", "3.8", "3.9", "3.10"], glibc_versions = [(2, 14), (2, 17)], muslc_versions = [(1, 1)], osx_versions = [(10, 9), (11, 0)], diff --git a/tests/pypi/generate_whl_library_build_bazel/generate_whl_library_build_bazel_tests.bzl b/tests/pypi/generate_whl_library_build_bazel/generate_whl_library_build_bazel_tests.bzl index a860681ae9..94530117cd 100644 --- a/tests/pypi/generate_whl_library_build_bazel/generate_whl_library_build_bazel_tests.bzl +++ b/tests/pypi/generate_whl_library_build_bazel/generate_whl_library_build_bazel_tests.bzl @@ -160,7 +160,7 @@ py_library( config_setting( name = "is_python_3.10_linux_ppc", flag_values = { - "@rules_python//python/config_settings:_python_version_major_minor": "3.10", + "@rules_python//python/config_settings:python_version_major_minor": "3.10", }, constraint_values = [ "@platforms//cpu:ppc", @@ -172,7 +172,7 @@ config_setting( config_setting( name = "is_python_3.9_anyos_aarch64", flag_values = { - "@rules_python//python/config_settings:_python_version_major_minor": "3.9", + "@rules_python//python/config_settings:python_version_major_minor": "3.9", }, constraint_values = ["@platforms//cpu:aarch64"], visibility = ["//visibility:private"], @@ -181,7 +181,7 @@ config_setting( config_setting( name = "is_python_3.9_linux_anyarch", flag_values = { - "@rules_python//python/config_settings:_python_version_major_minor": "3.9", + "@rules_python//python/config_settings:python_version_major_minor": "3.9", }, constraint_values = ["@platforms//os:linux"], visibility = ["//visibility:private"], 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 09a06311fc..9de309b295 100644 --- a/tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl +++ b/tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl @@ -110,7 +110,6 @@ _tests.append(_test_legacy_aliases) def _test_bzlmod_aliases(env): # Use this function as it is used in pip_repository actual = render_multiplatform_pkg_aliases( - default_config_setting = "//:my_config_setting", aliases = { "bar-baz": [ whl_alias(version = "3.2", repo = "pypi_32_bar_baz", config_setting = "//:my_config_setting"), @@ -124,6 +123,23 @@ load("@bazel_skylib//lib:selects.bzl", "selects") package(default_visibility = ["//visibility:public"]) +_NO_MATCH_ERROR = \"\"\"\\ +No matching wheel for current configuration's Python version. + +The current build configuration's Python version doesn't match any of the Python +wheels available for this wheel. This wheel supports the following Python +configuration settings: + //:my_config_setting + +To determine the current configuration's Python version, run: + `bazel config ` (shown further below) +and look for + rules_python//python/config_settings:python_version + +If the value is missing, then the "default" Python version is being used, +which has a "null" version value and will not match version constraints. +\"\"\" + alias( name = "bar_baz", actual = ":pkg", @@ -133,11 +149,9 @@ alias( name = "pkg", actual = selects.with_or( { - ( - "//:my_config_setting", - "//conditions:default", - ): "@pypi_32_bar_baz//:pkg", + "//:my_config_setting": "@pypi_32_bar_baz//:pkg", }, + no_match_error = _NO_MATCH_ERROR, ), ) @@ -145,11 +159,9 @@ alias( name = "whl", actual = selects.with_or( { - ( - "//:my_config_setting", - "//conditions:default", - ): "@pypi_32_bar_baz//:whl", + "//:my_config_setting": "@pypi_32_bar_baz//:whl", }, + no_match_error = _NO_MATCH_ERROR, ), ) @@ -157,11 +169,9 @@ alias( name = "data", actual = selects.with_or( { - ( - "//:my_config_setting", - "//conditions:default", - ): "@pypi_32_bar_baz//:data", + "//:my_config_setting": "@pypi_32_bar_baz//:data", }, + no_match_error = _NO_MATCH_ERROR, ), ) @@ -169,11 +179,9 @@ alias( name = "dist_info", actual = selects.with_or( { - ( - "//:my_config_setting", - "//conditions:default", - ): "@pypi_32_bar_baz//:dist_info", + "//:my_config_setting": "@pypi_32_bar_baz//:dist_info", }, + no_match_error = _NO_MATCH_ERROR, ), )""" @@ -198,7 +206,6 @@ _tests.append(_test_bzlmod_aliases) def _test_bzlmod_aliases_with_no_default_version(env): actual = render_multiplatform_pkg_aliases( - default_config_setting = None, aliases = { "bar-baz": [ whl_alias( @@ -291,106 +298,8 @@ alias( _tests.append(_test_bzlmod_aliases_with_no_default_version) -def _test_bzlmod_aliases_for_non_root_modules(env): - actual = render_pkg_aliases( - # 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_config_setting is not in the list of the versions in the - # whl_map. - default_config_setting = "//_config:is_python_3.3", - aliases = { - "bar-baz": [ - whl_alias(version = "3.2", repo = "pypi_32_bar_baz"), - whl_alias(version = "3.1", repo = "pypi_31_bar_baz"), - ], - }, - ) - - want_key = "bar_baz/BUILD.bazel" - want_content = """\ -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = ["//visibility:public"]) - -_NO_MATCH_ERROR = \"\"\"\\ -No matching wheel for current configuration's Python version. - -The current build configuration's Python version doesn't match any of the Python -wheels available for this wheel. This wheel supports the following Python -configuration settings: - //_config:is_python_3.1 - //_config:is_python_3.2 - -To determine the current configuration's Python version, run: - `bazel config ` (shown further below) -and look for - rules_python//python/config_settings:python_version - -If the value is missing, then the "default" Python version is being used, -which has a "null" version value and will not match version constraints. -\"\"\" - -alias( - name = "bar_baz", - actual = ":pkg", -) - -alias( - name = "pkg", - actual = selects.with_or( - { - "//_config:is_python_3.1": "@pypi_31_bar_baz//:pkg", - "//_config:is_python_3.2": "@pypi_32_bar_baz//:pkg", - }, - no_match_error = _NO_MATCH_ERROR, - ), -) - -alias( - name = "whl", - actual = selects.with_or( - { - "//_config:is_python_3.1": "@pypi_31_bar_baz//:whl", - "//_config:is_python_3.2": "@pypi_32_bar_baz//:whl", - }, - no_match_error = _NO_MATCH_ERROR, - ), -) - -alias( - name = "data", - actual = selects.with_or( - { - "//_config:is_python_3.1": "@pypi_31_bar_baz//:data", - "//_config:is_python_3.2": "@pypi_32_bar_baz//:data", - }, - no_match_error = _NO_MATCH_ERROR, - ), -) - -alias( - name = "dist_info", - actual = selects.with_or( - { - "//_config:is_python_3.1": "@pypi_31_bar_baz//:dist_info", - "//_config:is_python_3.2": "@pypi_32_bar_baz//:dist_info", - }, - no_match_error = _NO_MATCH_ERROR, - ), -)""" - - env.expect.that_collection(actual.keys()).contains_exactly([want_key]) - env.expect.that_str(actual[want_key]).equals(want_content) - -_tests.append(_test_bzlmod_aliases_for_non_root_modules) - def _test_aliases_are_created_for_all_wheels(env): actual = render_pkg_aliases( - default_config_setting = "//_config:is_python_3.2", aliases = { "bar": [ whl_alias(version = "3.1", repo = "pypi_31_bar"), @@ -414,7 +323,6 @@ _tests.append(_test_aliases_are_created_for_all_wheels) def _test_aliases_with_groups(env): actual = render_pkg_aliases( - default_config_setting = "//_config:is_python_3.2", aliases = { "bar": [ whl_alias(version = "3.1", repo = "pypi_31_bar"), @@ -555,13 +463,12 @@ def _test_config_settings( *, filename, want, + python_version, want_versions = {}, target_platforms = [], glibc_versions = [], muslc_versions = [], - osx_versions = [], - python_version = "", - python_default = True): + osx_versions = []): got, got_default_version_settings = get_filename_config_settings( filename = filename, target_platforms = target_platforms, @@ -569,7 +476,6 @@ def _test_config_settings( muslc_versions = muslc_versions, osx_versions = osx_versions, python_version = python_version, - python_default = python_default, ) env.expect.that_collection(got).contains_exactly(want) env.expect.that_dict(got_default_version_settings).contains_exactly(want_versions) @@ -580,42 +486,21 @@ def _test_sdist(env): _test_config_settings( env, filename = "foo-0.0.1" + ext, - want = [":is_sdist"], + python_version = "3.2", + want = [":is_cp3.2_sdist"], ) ext = ".zip" - _test_config_settings( - env, - filename = "foo-0.0.1" + ext, - target_platforms = [ - "linux_aarch64", - ], - want = [":is_sdist_linux_aarch64"], - ) - - _test_config_settings( - env, - filename = "foo-0.0.1" + ext, - python_version = "3.2", - want = [ - ":is_sdist", - ":is_cp3.2_sdist", - ], - ) - _test_config_settings( env, filename = "foo-0.0.1" + ext, python_version = "3.2", - python_default = True, target_platforms = [ "linux_aarch64", "linux_x86_64", ], want = [ - ":is_sdist_linux_aarch64", ":is_cp3.2_sdist_linux_aarch64", - ":is_sdist_linux_x86_64", ":is_cp3.2_sdist_linux_x86_64", ], ) @@ -623,28 +508,11 @@ def _test_sdist(env): _tests.append(_test_sdist) def _test_py2_py3_none_any(env): - _test_config_settings( - env, - filename = "foo-0.0.1-py2.py3-none-any.whl", - want = [":is_py_none_any"], - ) - - _test_config_settings( - env, - filename = "foo-0.0.1-py2.py3-none-any.whl", - target_platforms = [ - "linux_aarch64", - ], - want = [":is_py_none_any_linux_aarch64"], - ) - _test_config_settings( env, filename = "foo-0.0.1-py2.py3-none-any.whl", python_version = "3.2", - python_default = True, want = [ - ":is_py_none_any", ":is_cp3.2_py_none_any", ], ) @@ -653,13 +521,10 @@ def _test_py2_py3_none_any(env): env, filename = "foo-0.0.1-py2.py3-none-any.whl", python_version = "3.2", - python_default = False, target_platforms = [ "osx_x86_64", ], - want = [ - ":is_cp3.2_py_none_any_osx_x86_64", - ], + want = [":is_cp3.2_py_none_any_osx_x86_64"], ) _tests.append(_test_py2_py3_none_any) @@ -668,14 +533,16 @@ def _test_py3_none_any(env): _test_config_settings( env, filename = "foo-0.0.1-py3-none-any.whl", - want = [":is_py3_none_any"], + python_version = "3.1", + want = [":is_cp3.1_py3_none_any"], ) _test_config_settings( env, filename = "foo-0.0.1-py3-none-any.whl", + python_version = "3.1", target_platforms = ["linux_x86_64"], - want = [":is_py3_none_any_linux_x86_64"], + want = [":is_cp3.1_py3_none_any_linux_x86_64"], ) _tests.append(_test_py3_none_any) @@ -684,19 +551,20 @@ def _test_py3_none_macosx_10_9_universal2(env): _test_config_settings( env, filename = "foo-0.0.1-py3-none-macosx_10_9_universal2.whl", + python_version = "3.1", osx_versions = [ (10, 9), (11, 0), ], want = [], want_versions = { - ":is_py3_none_osx_aarch64_universal2": { - (10, 9): ":is_py3_none_osx_10_9_aarch64_universal2", - (11, 0): ":is_py3_none_osx_11_0_aarch64_universal2", + ":is_cp3.1_py3_none_osx_aarch64_universal2": { + (10, 9): ":is_cp3.1_py3_none_osx_10_9_aarch64_universal2", + (11, 0): ":is_cp3.1_py3_none_osx_11_0_aarch64_universal2", }, - ":is_py3_none_osx_x86_64_universal2": { - (10, 9): ":is_py3_none_osx_10_9_x86_64_universal2", - (11, 0): ":is_py3_none_osx_11_0_x86_64_universal2", + ":is_cp3.1_py3_none_osx_x86_64_universal2": { + (10, 9): ":is_cp3.1_py3_none_osx_10_9_x86_64_universal2", + (11, 0): ":is_cp3.1_py3_none_osx_11_0_x86_64_universal2", }, }, ) @@ -707,20 +575,8 @@ def _test_cp37_abi3_linux_x86_64(env): _test_config_settings( env, filename = "foo-0.0.1-cp37-abi3-linux_x86_64.whl", - want = [ - ":is_cp3x_abi3_linux_x86_64", - ], - ) - - _test_config_settings( - env, - filename = "foo-0.0.1-cp37-abi3-linux_x86_64.whl", - python_version = "3.2", - python_default = True, - want = [ - ":is_cp3x_abi3_linux_x86_64", - ":is_cp3.2_cp3x_abi3_linux_x86_64", - ], + python_version = "3.7", + want = [":is_cp3.7_cp3x_abi3_linux_x86_64"], ) _tests.append(_test_cp37_abi3_linux_x86_64) @@ -729,9 +585,8 @@ def _test_cp37_abi3_windows_x86_64(env): _test_config_settings( env, filename = "foo-0.0.1-cp37-abi3-windows_x86_64.whl", - want = [ - ":is_cp3x_abi3_windows_x86_64", - ], + python_version = "3.7", + want = [":is_cp3.7_cp3x_abi3_windows_x86_64"], ) _tests.append(_test_cp37_abi3_windows_x86_64) @@ -740,6 +595,7 @@ def _test_cp37_abi3_manylinux_2_17_x86_64(env): _test_config_settings( env, filename = "foo-0.0.1-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", + python_version = "3.7", glibc_versions = [ (2, 16), (2, 17), @@ -747,9 +603,9 @@ def _test_cp37_abi3_manylinux_2_17_x86_64(env): ], want = [], want_versions = { - ":is_cp3x_abi3_manylinux_x86_64": { - (2, 17): ":is_cp3x_abi3_manylinux_2_17_x86_64", - (2, 18): ":is_cp3x_abi3_manylinux_2_18_x86_64", + ":is_cp3.7_cp3x_abi3_manylinux_x86_64": { + (2, 17): ":is_cp3.7_cp3x_abi3_manylinux_2_17_x86_64", + (2, 18): ":is_cp3.7_cp3x_abi3_manylinux_2_18_x86_64", }, }, ) @@ -761,6 +617,7 @@ def _test_cp37_abi3_manylinux_2_17_musllinux_1_1_aarch64(env): _test_config_settings( env, filename = "foo-0.0.1-cp37-cp37-manylinux_2_17_arm64.musllinux_1_1_arm64.whl", + python_version = "3.7", glibc_versions = [ (2, 16), (2, 17), @@ -771,12 +628,12 @@ def _test_cp37_abi3_manylinux_2_17_musllinux_1_1_aarch64(env): ], want = [], want_versions = { - ":is_cp3x_cp_manylinux_aarch64": { - (2, 17): ":is_cp3x_cp_manylinux_2_17_aarch64", - (2, 18): ":is_cp3x_cp_manylinux_2_18_aarch64", + ":is_cp3.7_cp3x_cp_manylinux_aarch64": { + (2, 17): ":is_cp3.7_cp3x_cp_manylinux_2_17_aarch64", + (2, 18): ":is_cp3.7_cp3x_cp_manylinux_2_18_aarch64", }, - ":is_cp3x_cp_musllinux_aarch64": { - (1, 1): ":is_cp3x_cp_musllinux_1_1_aarch64", + ":is_cp3.7_cp3x_cp_musllinux_aarch64": { + (1, 1): ":is_cp3.7_cp3x_cp_musllinux_1_1_aarch64", }, }, ) @@ -785,7 +642,7 @@ _tests.append(_test_cp37_abi3_manylinux_2_17_musllinux_1_1_aarch64) def _test_multiplatform_whl_aliases_empty(env): # Check that we still work with an empty requirements.txt - got = multiplatform_whl_aliases(aliases = [], default_version = None) + got = multiplatform_whl_aliases(aliases = []) env.expect.that_collection(got).contains_exactly([]) _tests.append(_test_multiplatform_whl_aliases_empty) @@ -798,7 +655,7 @@ def _test_multiplatform_whl_aliases_nofilename(env): version = "3.1", ), ] - got = multiplatform_whl_aliases(aliases = aliases, default_version = None) + got = multiplatform_whl_aliases(aliases = aliases) env.expect.that_collection(got).contains_exactly(aliases) _tests.append(_test_multiplatform_whl_aliases_nofilename) @@ -827,7 +684,6 @@ def _test_multiplatform_whl_aliases_filename(env): ] got = multiplatform_whl_aliases( aliases = aliases, - default_version = "3.1", glibc_versions = [], muslc_versions = [], osx_versions = [], @@ -837,9 +693,6 @@ def _test_multiplatform_whl_aliases_filename(env): whl_alias(config_setting = "//_config:is_cp3.1_py3_none_any_linux_aarch64", repo = "foo-0.0.2", version = "3.1"), whl_alias(config_setting = "//_config:is_cp3.1_py3_none_any_linux_x86_64", repo = "foo-0.0.2", version = "3.1"), whl_alias(config_setting = "//_config:is_cp3.2_py3_none_any", repo = "foo-py3-0.0.3", version = "3.2"), - whl_alias(config_setting = "//_config:is_py3_none_any", repo = "foo-py3-0.0.1", version = "3.1"), - whl_alias(config_setting = "//_config:is_py3_none_any_linux_aarch64", repo = "foo-0.0.2", version = "3.1"), - whl_alias(config_setting = "//_config:is_py3_none_any_linux_x86_64", repo = "foo-0.0.2", version = "3.1"), ] env.expect.that_collection(got).contains_exactly(want) @@ -865,7 +718,6 @@ def _test_multiplatform_whl_aliases_filename_versioned(env): ] got = multiplatform_whl_aliases( aliases = aliases, - default_version = None, glibc_versions = [(2, 17), (2, 18)], muslc_versions = [(1, 1), (1, 2)], osx_versions = [], @@ -931,7 +783,6 @@ def _test_config_settings_exist(env): got_aliases = multiplatform_whl_aliases( aliases = aliases, - default_version = None, glibc_versions = kwargs.get("glibc_versions", []), muslc_versions = kwargs.get("muslc_versions", []), osx_versions = kwargs.get("osx_versions", []), diff --git a/tests/python/python_tests.bzl b/tests/python/python_tests.bzl index 101313da4f..40504302d1 100644 --- a/tests/python/python_tests.bzl +++ b/tests/python/python_tests.bzl @@ -14,8 +14,8 @@ "" +load("@pythons_hub//:versions.bzl", "MINOR_MAPPING") load("@rules_testing//lib:test_suite.bzl", "test_suite") -load("//python:versions.bzl", "MINOR_MAPPING") load("//python/private:python.bzl", "parse_modules") # buildifier: disable=bzl-visibility _tests = [] @@ -451,6 +451,7 @@ def _test_add_new_version(env): "url": {"aarch64-unknown-linux-gnu": ["something.org", "else.org"]}, }) env.expect.that_dict(py.config.minor_mapping).contains_exactly({ + "3.12": "3.12.4", # The `minor_mapping` will be overriden only for the missing keys "3.13": "3.13.0", }) env.expect.that_collection(py.toolchains).contains_exactly([