Skip to content

Commit 23e7f7f

Browse files
committed
feat(pypi) Handle local version in requirement parsing
1 parent 79bd1f5 commit 23e7f7f

File tree

5 files changed

+68
-5
lines changed

5 files changed

+68
-5
lines changed

.bazelrc

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
# (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it)
55
# To update these lines, execute
66
# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
7-
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
8-
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
7+
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
8+
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
99

1010
test --test_output=errors
1111

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ Unreleased changes template.
8080
### Fixed
8181
* (rules) Don't drop custom import paths if Bazel-builtin PyInfo is removed.
8282
([2414](https://github.com/bazelbuild/rules_python/issues/2414)).
83+
* (pypi): Correctly handle multiple versions of the same package in the requirements
84+
files which is useful when including different PyTorch builds (e.g. <pytorch+cpu> vs <pytorch+cu118> ) for different target platforms.
85+
Fixes ([2337](https://github.com/bazelbuild/rules_python/issues/2337)).
8386

8487
{#v0-40-added}
8588
### Added

examples/bzlmod/MODULE.bazel.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/private/pypi/parse_requirements.bzl

+15-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ load(":index_sources.bzl", "index_sources")
3232
load(":parse_requirements_txt.bzl", "parse_requirements_txt")
3333
load(":whl_target_platforms.bzl", "select_whls")
3434

35+
def _extract_version(entry):
36+
"""Extract the version part from the requirement string.
37+
38+
39+
Args:
40+
entry: {type}`str` The requirement string.
41+
"""
42+
version_start = entry.find("==")
43+
if version_start != -1:
44+
# Extract everything after '==' until the next space or end of the string
45+
version, _, _ = entry[version_start + 2:].partition(" ")
46+
return version
47+
return None
48+
3549
def parse_requirements(
3650
ctx,
3751
*,
@@ -92,7 +106,7 @@ def parse_requirements(
92106
# are returned as just the base package name. e.g., `foo[bar]` results
93107
# in an entry like `("foo", "foo[bar] == 1.0 ...")`.
94108
requirements_dict = {
95-
normalize_name(entry[0]): entry
109+
(normalize_name(entry[0]), _extract_version(entry[1])): entry
96110
for entry in sorted(
97111
parse_result.requirements,
98112
# Get the longest match and fallback to original WORKSPACE sorting,

tests/pypi/parse_requirements/parse_requirements_tests.bzl

+46
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ load("//python/private/pypi:parse_requirements.bzl", "parse_requirements", "sele
1919

2020
def _mock_ctx():
2121
testdata = {
22+
"requirements_different_package_version": """\
23+
foo==0.0.1+local --hash=sha256:deadbeef
24+
foo==0.0.1 --hash=sha256:deadb00f
25+
""",
2226
"requirements_direct": """\
2327
foo[extra] @ https://some-url
2428
""",
@@ -382,6 +386,48 @@ def _test_env_marker_resolution(env):
382386

383387
_tests.append(_test_env_marker_resolution)
384388

389+
def _test_different_package_version(env):
390+
got = parse_requirements(
391+
ctx = _mock_ctx(),
392+
requirements_by_platform = {
393+
"requirements_different_package_version": ["linux_x86_64"],
394+
},
395+
)
396+
env.expect.that_dict(got).contains_exactly({
397+
"foo": [
398+
struct(
399+
distribution = "foo",
400+
extra_pip_args = [],
401+
requirement_line = "foo==0.0.1 --hash=sha256:deadb00f",
402+
srcs = struct(
403+
requirement = "foo==0.0.1",
404+
shas = ["deadb00f"],
405+
version = "0.0.1",
406+
),
407+
target_platforms = ["linux_x86_64"],
408+
whls = [],
409+
sdist = None,
410+
is_exposed = True,
411+
),
412+
struct(
413+
distribution = "foo",
414+
extra_pip_args = [],
415+
requirement_line = "foo==0.0.1+local --hash=sha256:deadbeef",
416+
srcs = struct(
417+
requirement = "foo==0.0.1+local",
418+
shas = ["deadbeef"],
419+
version = "0.0.1+local",
420+
),
421+
target_platforms = ["linux_x86_64"],
422+
whls = [],
423+
sdist = None,
424+
is_exposed = True,
425+
),
426+
],
427+
})
428+
429+
_tests.append(_test_different_package_version)
430+
385431
def parse_requirements_test_suite(name):
386432
"""Create the test suite.
387433

0 commit comments

Comments
 (0)