Skip to content

Commit a18ae49

Browse files
authored
fix: Fix incorrectly generated Required-Dist when specifying requirements with markers in extra_requires in py_wheel rule (bazel-contrib#2200)
Currently, if extra requirements are provided via a file, it is allowed to contain markers, but if it is passed via extra_requires field, it will run into error since the extra in this case is blindly added in the following line in `py_wheel.bzl` ``` metadata_contents.append( "Requires-Dist: %s; extra == '%s'" % (requirement, option), ) ``` Thus, this PR adds a post-process for this case, to make it possible to pass something like ``` extra_requires = {"example": [ "pyyaml>=6.0.0,!=6.0.1", 'toml; (python_version == "3.11" or python_version == "3.12") and python_version != "3.8"', 'wheel; python_version == "3.11" or python_version == "3.12" ', ]}, ``` to `py_wheel`
1 parent 148122a commit a18ae49

4 files changed

Lines changed: 81 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ A brief description of the categories of changes:
5151
{obj}`--bootstrap_impl=script`. This fixes invocations using non-sandboxed
5252
test execution with `--enable_runfiles=false --build_runfile_manifests=true`.
5353
([#2186](https://github.com/bazelbuild/rules_python/issues/2186)).
54+
* (py_wheel) Fix incorrectly generated `Required-Dist` when specifying requirements with markers
55+
in extra_requires in py_wheel rule.
5456

5557

5658
### Added

examples/wheel/BUILD.bazel

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,27 @@ py_wheel(
333333
version = "0.0.1",
334334
)
335335

336+
py_wheel(
337+
name = "extra_requires",
338+
distribution = "extra_requires",
339+
extra_requires = {"example": [
340+
"pyyaml>=6.0.0,!=6.0.1",
341+
'toml; (python_version == "3.11" or python_version == "3.12") and python_version != "3.8"',
342+
'wheel; python_version == "3.11" or python_version == "3.12" ',
343+
]},
344+
python_tag = "py3",
345+
# py_wheel can use text files to specify their requirements. This
346+
# can be convenient for users of `compile_pip_requirements` who have
347+
# granular `requirements.in` files per package.
348+
requires = [
349+
"tomli>=2.0.0",
350+
"starlark",
351+
'pytest; python_version != "3.8"',
352+
],
353+
version = "0.0.1",
354+
deps = [":example_pkg"],
355+
)
356+
336357
py_test(
337358
name = "wheel_test",
338359
srcs = ["wheel_test.py"],
@@ -341,6 +362,7 @@ py_test(
341362
":custom_package_root_multi_prefix",
342363
":custom_package_root_multi_prefix_reverse_order",
343364
":customized",
365+
":extra_requires",
344366
":filename_escaping",
345367
":minimal_data_files",
346368
":minimal_with_py_library",

examples/wheel/wheel_test.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,36 @@ def test_minimal_data_files(self):
489489
],
490490
)
491491

492+
def test_extra_requires(self):
493+
filename = self._get_path("extra_requires-0.0.1-py3-none-any.whl")
494+
495+
with zipfile.ZipFile(filename) as zf:
496+
self.assertAllEntriesHasReproducibleMetadata(zf)
497+
metadata_file = None
498+
for f in zf.namelist():
499+
if os.path.basename(f) == "METADATA":
500+
metadata_file = f
501+
self.assertIsNotNone(metadata_file)
502+
503+
requires = []
504+
with zf.open(metadata_file) as fp:
505+
for line in fp:
506+
if line.startswith(b"Requires-Dist:"):
507+
requires.append(line.decode("utf-8").strip())
508+
509+
print(requires)
510+
self.assertEqual(
511+
[
512+
"Requires-Dist: tomli>=2.0.0",
513+
"Requires-Dist: starlark",
514+
'Requires-Dist: pytest; python_version != "3.8"',
515+
"Requires-Dist: pyyaml!=6.0.1,>=6.0.0; extra == 'example'",
516+
'Requires-Dist: toml; ((python_version == "3.11" or python_version == "3.12") and python_version != "3.8") and extra == \'example\'',
517+
'Requires-Dist: wheel; (python_version == "3.11" or python_version == "3.12") and extra == \'example\'',
518+
],
519+
requires,
520+
)
521+
492522

493523
if __name__ == "__main__":
494524
unittest.main()

tools/wheelmaker.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -537,9 +537,34 @@ def main() -> None:
537537

538538
# Search for any `Requires-Dist` entries that refer to other files and
539539
# expand them.
540+
541+
def get_new_requirement_line(reqs_text, extra):
542+
req = Requirement(reqs_text.strip())
543+
if req.marker:
544+
if extra:
545+
return f"Requires-Dist: {req.name}{req.specifier}; ({req.marker}) and {extra}"
546+
else:
547+
return f"Requires-Dist: {req.name}{req.specifier}; {req.marker}"
548+
else:
549+
return f"Requires-Dist: {req.name}{req.specifier}; {extra}".strip(" ;")
550+
540551
for meta_line in metadata.splitlines():
541-
if not meta_line.startswith("Requires-Dist: @"):
552+
if not meta_line.startswith("Requires-Dist: "):
542553
continue
554+
555+
if not meta_line[len("Requires-Dist: ") :].startswith("@"):
556+
# This is a normal requirement.
557+
package, _, extra = meta_line[len("Requires-Dist: ") :].rpartition(";")
558+
if not package:
559+
# This is when the package requirement does not have markers.
560+
continue
561+
extra = extra.strip()
562+
metadata = metadata.replace(
563+
meta_line, get_new_requirement_line(package, extra)
564+
)
565+
continue
566+
567+
# This is a requirement that refers to a file.
543568
file, _, extra = meta_line[len("Requires-Dist: @") :].partition(";")
544569
extra = extra.strip()
545570

@@ -552,20 +577,7 @@ def main() -> None:
552577
# Strip any comments
553578
reqs_text, _, _ = reqs_text.partition("#")
554579

555-
req = Requirement(reqs_text.strip())
556-
if req.marker:
557-
if extra:
558-
reqs.append(
559-
f"Requires-Dist: {req.name}{req.specifier}; ({req.marker}) and {extra}"
560-
)
561-
else:
562-
reqs.append(
563-
f"Requires-Dist: {req.name}{req.specifier}; {req.marker}"
564-
)
565-
else:
566-
reqs.append(
567-
f"Requires-Dist: {req.name}{req.specifier}; {extra}".strip(" ;")
568-
)
580+
reqs.append(get_new_requirement_line(reqs_text, extra))
569581

570582
metadata = metadata.replace(meta_line, "\n".join(reqs))
571583

0 commit comments

Comments
 (0)