diff --git a/CHANGELOG.md b/CHANGELOG.md index 95d1dc8530..f21f9bb3cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ A brief description of the categories of changes: ([617](https://github.com/bazelbuild/rules_python/issues/617)). * (pypi) When {attr}`pip.parse.experimental_index_url` is set, we need to still pass the `extra_pip_args` value when building an `sdist`. +* (pypi) The patched wheel filenames from now on are using local version specifiers + which fixes usage of the said wheels using standard package managers. {#v0-0-0-added} ### Added diff --git a/examples/bzlmod/MODULE.bazel.lock b/examples/bzlmod/MODULE.bazel.lock index 6e7d780a26..d34f4ecb73 100644 --- a/examples/bzlmod/MODULE.bazel.lock +++ b/examples/bzlmod/MODULE.bazel.lock @@ -1392,7 +1392,7 @@ }, "@@rules_python~//python/extensions:pip.bzl%pip": { "general": { - "bzlTransitiveDigest": "HF4Ob8+IVv7X7DHag07k47pv+QywfyjKF8Z6Q7M5/oU=", + "bzlTransitiveDigest": "qxyKk6sb6G2WeW3iUlRmVO5jafUab5qPwz66Y2anPp8=", "usagesDigest": "MChlcSw99EuW3K7OOoMcXQIdcJnEh6YmfyjJm+9mxIg=", "recordedFileInputs": { "@@other_module~//requirements_lock_3_11.txt": "a7d0061366569043d5efcf80e34a32c732679367cb3c831c4cdc606adc36d314", @@ -6581,7 +6581,7 @@ }, "@@rules_python~//python/private/pypi:pip.bzl%pip_internal": { "general": { - "bzlTransitiveDigest": "oEqeANhT7TnWlFpmzRhRdWn9kCRKTen7mIV72CWlAIA=", + "bzlTransitiveDigest": "6NoEDGeQugmtzNzf4Emcb8Sb/cW3RTxSSA6DTHLB1/A=", "usagesDigest": "LYtSAPzhPjmfD9vF39mCED1UQSvHEo2Hv+aK5Z4ZWWc=", "recordedFileInputs": { "@@rules_python~//tools/publish/requirements_linux.txt": "8175b4c8df50ae2f22d1706961884beeb54e7da27bd2447018314a175981997d", diff --git a/python/private/pypi/patch_whl.bzl b/python/private/pypi/patch_whl.bzl index 74cd890bad..a7da224321 100644 --- a/python/private/pypi/patch_whl.bzl +++ b/python/private/pypi/patch_whl.bzl @@ -32,6 +32,39 @@ load(":parse_whl_name.bzl", "parse_whl_name") _rules_python_root = Label("//:BUILD.bazel") +def patched_whl_name(original_whl_name): + """Return the new filename to output the patched wheel. + + Args: + original_whl_name: {type}`str` the whl name of the original file. + + Returns: + {type}`str` an output name to write the patched wheel to. + """ + parsed_whl = parse_whl_name(original_whl_name) + version = parsed_whl.version + suffix = "patched" + if "+" in version: + # This already has some local version, so we just append one more + # identifier here. We comply with the spec and mark the file as patched + # by adding a local version identifier at the end. + # + # By doing this we can still install the package using most of the package + # managers + # + # See https://packaging.python.org/en/latest/specifications/version-specifiers/#local-version-identifiers + version = "{}.{}".format(version, suffix) + else: + version = "{}+{}".format(version, suffix) + + return "{distribution}-{version}-{python_tag}-{abi_tag}-{platform_tag}.whl".format( + distribution = parsed_whl.distribution, + version = version, + python_tag = parsed_whl.python_tag, + abi_tag = parsed_whl.abi_tag, + platform_tag = parsed_whl.platform_tag, + ) + def patch_whl(rctx, *, python_interpreter, whl_path, patches, **kwargs): """Patch a whl file and repack it to ensure that the RECORD metadata stays correct. @@ -66,18 +99,8 @@ def patch_whl(rctx, *, python_interpreter, whl_path, patches, **kwargs): for patch_file, patch_strip in patches.items(): rctx.patch(patch_file, strip = patch_strip) - # Generate an output filename, which we will be returning - parsed_whl = parse_whl_name(whl_input.basename) - whl_patched = "{}.whl".format("-".join([ - parsed_whl.distribution, - parsed_whl.version, - (parsed_whl.build_tag or "") + "patched", - parsed_whl.python_tag, - parsed_whl.abi_tag, - parsed_whl.platform_tag, - ])) - record_patch = rctx.path("RECORD.patch") + whl_patched = patched_whl_name(whl_input.basename) repo_utils.execute_checked( rctx, diff --git a/tests/pypi/patch_whl/BUILD.bazel b/tests/pypi/patch_whl/BUILD.bazel new file mode 100644 index 0000000000..d6c4f47b36 --- /dev/null +++ b/tests/pypi/patch_whl/BUILD.bazel @@ -0,0 +1,3 @@ +load(":patch_whl_tests.bzl", "patch_whl_test_suite") + +patch_whl_test_suite(name = "patch_whl_tests") diff --git a/tests/pypi/patch_whl/patch_whl_tests.bzl b/tests/pypi/patch_whl/patch_whl_tests.bzl new file mode 100644 index 0000000000..f93fe459c9 --- /dev/null +++ b/tests/pypi/patch_whl/patch_whl_tests.bzl @@ -0,0 +1,40 @@ +# Copyright 2024 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"" + +load("@rules_testing//lib:test_suite.bzl", "test_suite") +load("//python/private/pypi:patch_whl.bzl", "patched_whl_name") # buildifier: disable=bzl-visibility + +_tests = [] + +def _test_simple(env): + got = patched_whl_name("foo-1.2.3-py3-none-any.whl") + env.expect.that_str(got).equals("foo-1.2.3+patched-py3-none-any.whl") + +_tests.append(_test_simple) + +def _test_simple_local_version(env): + got = patched_whl_name("foo-1.2.3+special-py3-none-any.whl") + env.expect.that_str(got).equals("foo-1.2.3+special.patched-py3-none-any.whl") + +_tests.append(_test_simple_local_version) + +def patch_whl_test_suite(name): + """Create the test suite. + + Args: + name: the name of the test suite + """ + test_suite(name = name, basic_tests = _tests)