Skip to content

Commit 948fcec

Browse files
authored
fix(pypi): correctly aggregate the requirements files (bazel-contrib#2932)
This implements the actual fix where we are aggregating the whls and sdists correctly from multiple different requirements lines. Fixes bazel-contrib#2648. Closes bazel-contrib#2658.
1 parent 02198f6 commit 948fcec

File tree

3 files changed

+97
-7
lines changed

3 files changed

+97
-7
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ END_UNRELEASED_TEMPLATE
9696
* (pypi) When running under `bazel test`, be sure that temporary `requirements` file
9797
remains writable.
9898
* (py_test, py_binary) Allow external files to be used for main
99+
* (pypi) Correctly aggregate the sources when the hashes specified in the lockfile differ
100+
by platform even though the same version is used. Fixes [#2648](https://github.com/bazel-contrib/rules_python/issues/2648).
99101

100102
{#v0-0-0-added}
101103
### Added

python/private/pypi/parse_requirements.bzl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ def _package_srcs(
223223
env_marker_target_platforms,
224224
extract_url_srcs):
225225
"""A function to return sources for a particular package."""
226-
srcs = []
226+
srcs = {}
227227
for r in sorted(reqs.values(), key = lambda r: r.requirement_line):
228228
whls, sdist = _add_dists(
229229
requirement = r,
@@ -249,21 +249,31 @@ def _package_srcs(
249249
)]
250250
req_line = r.srcs.requirement_line
251251

252+
extra_pip_args = tuple(r.extra_pip_args)
252253
for dist in all_dists:
253-
srcs.append(
254+
key = (
255+
dist.filename,
256+
req_line,
257+
extra_pip_args,
258+
)
259+
entry = srcs.setdefault(
260+
key,
254261
struct(
255262
distribution = name,
256263
extra_pip_args = r.extra_pip_args,
257264
requirement_line = req_line,
258-
target_platforms = target_platforms,
265+
target_platforms = [],
259266
filename = dist.filename,
260267
sha256 = dist.sha256,
261268
url = dist.url,
262269
yanked = dist.yanked,
263270
),
264271
)
272+
for p in target_platforms:
273+
if p not in entry.target_platforms:
274+
entry.target_platforms.append(p)
265275

266-
return srcs
276+
return srcs.values()
267277

268278
def select_requirement(requirements, *, platform):
269279
"""A simple function to get a requirement for a particular platform.

tests/pypi/parse_requirements/parse_requirements_tests.bzl

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ foo[extra]==0.0.1 \
3838
foo @ git+https://github.com/org/foo.git@deadbeef
3939
""",
4040
"requirements_linux": """\
41-
foo==0.0.3 --hash=sha256:deadbaaf
41+
foo==0.0.3 --hash=sha256:deadbaaf --hash=sha256:5d15t
4242
""",
4343
# download_only = True
4444
"requirements_linux_download_only": """\
@@ -67,7 +67,7 @@ foo==0.0.4 @ https://example.org/foo-0.0.4.whl
6767
foo==0.0.5 @ https://example.org/foo-0.0.5.whl --hash=sha256:deadbeef
6868
""",
6969
"requirements_osx": """\
70-
foo==0.0.3 --hash=sha256:deadbaaf
70+
foo==0.0.3 --hash=sha256:deadbaaf --hash=sha256:deadb11f --hash=sha256:5d15t
7171
""",
7272
"requirements_osx_download_only": """\
7373
--platform=macosx_10_9_arm64
@@ -251,7 +251,7 @@ def _test_multi_os(env):
251251
struct(
252252
distribution = "foo",
253253
extra_pip_args = [],
254-
requirement_line = "foo==0.0.3 --hash=sha256:deadbaaf",
254+
requirement_line = "foo==0.0.3 --hash=sha256:deadbaaf --hash=sha256:5d15t",
255255
target_platforms = ["linux_x86_64"],
256256
url = "",
257257
filename = "",
@@ -515,6 +515,84 @@ def _test_git_sources(env):
515515

516516
_tests.append(_test_git_sources)
517517

518+
def _test_overlapping_shas_with_index_results(env):
519+
got = parse_requirements(
520+
ctx = _mock_ctx(),
521+
requirements_by_platform = {
522+
"requirements_linux": ["cp39_linux_x86_64"],
523+
"requirements_osx": ["cp39_osx_x86_64"],
524+
},
525+
get_index_urls = lambda _, __: {
526+
"foo": struct(
527+
sdists = {
528+
"5d15t": struct(
529+
url = "sdist",
530+
sha256 = "5d15t",
531+
filename = "foo-0.0.1.tar.gz",
532+
yanked = False,
533+
),
534+
},
535+
whls = {
536+
"deadb11f": struct(
537+
url = "super2",
538+
sha256 = "deadb11f",
539+
filename = "foo-0.0.1-py3-none-macosx_14_0_x86_64.whl",
540+
yanked = False,
541+
),
542+
"deadbaaf": struct(
543+
url = "super2",
544+
sha256 = "deadbaaf",
545+
filename = "foo-0.0.1-py3-none-any.whl",
546+
yanked = False,
547+
),
548+
},
549+
),
550+
},
551+
)
552+
553+
env.expect.that_collection(got).contains_exactly([
554+
struct(
555+
name = "foo",
556+
is_exposed = True,
557+
# TODO @aignas 2025-05-25: how do we rename this?
558+
is_multiple_versions = True,
559+
srcs = [
560+
struct(
561+
distribution = "foo",
562+
extra_pip_args = [],
563+
filename = "foo-0.0.1-py3-none-any.whl",
564+
requirement_line = "foo==0.0.3",
565+
sha256 = "deadbaaf",
566+
target_platforms = ["cp39_linux_x86_64", "cp39_osx_x86_64"],
567+
url = "super2",
568+
yanked = False,
569+
),
570+
struct(
571+
distribution = "foo",
572+
extra_pip_args = [],
573+
filename = "foo-0.0.1.tar.gz",
574+
requirement_line = "foo==0.0.3",
575+
sha256 = "5d15t",
576+
target_platforms = ["cp39_linux_x86_64", "cp39_osx_x86_64"],
577+
url = "sdist",
578+
yanked = False,
579+
),
580+
struct(
581+
distribution = "foo",
582+
extra_pip_args = [],
583+
filename = "foo-0.0.1-py3-none-macosx_14_0_x86_64.whl",
584+
requirement_line = "foo==0.0.3",
585+
sha256 = "deadb11f",
586+
target_platforms = ["cp39_osx_x86_64"],
587+
url = "super2",
588+
yanked = False,
589+
),
590+
],
591+
),
592+
])
593+
594+
_tests.append(_test_overlapping_shas_with_index_results)
595+
518596
def parse_requirements_test_suite(name):
519597
"""Create the test suite.
520598

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy