From 6462ff9734dee4848b4585fec707a5eb046eef7b Mon Sep 17 00:00:00 2001 From: martin4861 Date: Fri, 6 Feb 2026 08:46:47 +0100 Subject: [PATCH 1/9] Extract function get_new_requirement_line to make it testable --- tests/tools/wheelmaker_test.py | 10 +++++++++ tools/wheelmaker.py | 37 ++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/tests/tools/wheelmaker_test.py b/tests/tools/wheelmaker_test.py index 288dde720a..4bb0bd52df 100644 --- a/tests/tools/wheelmaker_test.py +++ b/tests/tools/wheelmaker_test.py @@ -71,5 +71,15 @@ def test_arcname_from(self) -> None: self.assertEqual(got, want) +class GetNewRequirementLineTest(unittest.TestCase): + def test_requirement(self): + result = wheelmaker.get_new_requirement_line("requests>=2.0", "") + self.assertEqual(result, "Requires-Dist: requests>=2.0") + + def test_requirement_and_extra(self): + result = wheelmaker.get_new_requirement_line("requests>=2.0", "extra=='dev'") + self.assertEqual(result, "Requires-Dist: requests>=2.0; extra=='dev'") + + if __name__ == "__main__": unittest.main() diff --git a/tools/wheelmaker.py b/tools/wheelmaker.py index 4390df3445..72a6ab2434 100644 --- a/tools/wheelmaker.py +++ b/tools/wheelmaker.py @@ -330,9 +330,7 @@ def add_wheelfile(self): Wheel-Version: 1.0 Generator: bazel-wheelmaker 1.0 Root-Is-Purelib: {} -""".format( - "true" if self._platform == "any" else "false" - ) +""".format("true" if self._platform == "any" else "false") for tag in self.disttags(): wheel_contents += "Tag: %s\n" % tag self._whlfile.add_string(self.distinfo_path("WHEEL"), wheel_contents) @@ -365,6 +363,24 @@ def get_files_to_package(input_files): return files +def get_new_requirement_line(reqs_text, extra): + from packaging.requirements import Requirement + + req = Requirement(reqs_text.strip()) + req_extra_deps = f"[{','.join(req.extras)}]" if req.extras else "" + if req.marker: + if extra: + return f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; ({req.marker}) and {extra}" + else: + return f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; {req.marker}" + else: + return ( + f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; {extra}".strip( + " ;" + ) + ) + + def resolve_argument_stamp( argument: str, volatile_status_stamp: Path, stable_status_stamp: Path ) -> str: @@ -430,7 +446,7 @@ def parse_args() -> argparse.Namespace: output_group.add_argument( "--name_file", type=Path, - help="A file where the canonical name of the " "wheel will be written", + help="A file where the canonical name of the wheel will be written", ) output_group.add_argument( @@ -578,19 +594,6 @@ def main() -> None: # Search for any `Requires-Dist` entries that refer to other files and # expand them. - def get_new_requirement_line(reqs_text, extra): - req = Requirement(reqs_text.strip()) - req_extra_deps = f"[{','.join(req.extras)}]" if req.extras else "" - if req.marker: - if extra: - return f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; ({req.marker}) and {extra}" - else: - return f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; {req.marker}" - else: - return f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; {extra}".strip( - " ;" - ) - for meta_line in metadata.splitlines(): if not meta_line.startswith("Requires-Dist: "): continue From 0dadc880b180b5772b50c595cf8bb8940f6817af Mon Sep 17 00:00:00 2001 From: martin4861 Date: Fri, 6 Feb 2026 08:51:25 +0100 Subject: [PATCH 2/9] Add test for Requires-Dist with url git --- tests/tools/wheelmaker_test.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/tools/wheelmaker_test.py b/tests/tools/wheelmaker_test.py index 4bb0bd52df..a2d4c951dd 100644 --- a/tests/tools/wheelmaker_test.py +++ b/tests/tools/wheelmaker_test.py @@ -80,6 +80,15 @@ def test_requirement_and_extra(self): result = wheelmaker.get_new_requirement_line("requests>=2.0", "extra=='dev'") self.assertEqual(result, "Requires-Dist: requests>=2.0; extra=='dev'") + def test_requirement_with_url(self): + result = wheelmaker.get_new_requirement_line( + "requests @ git+https://github.com/psf/requests.git@3aa6386c3", "" + ) + self.assertEqual( + result, + "Requires-Dist: requests @ git+https://github.com/psf/requests.git@3aa6386c3", + ) + if __name__ == "__main__": unittest.main() From c88d59cc1dddbd45ff9f03725fd3066b684c56c7 Mon Sep 17 00:00:00 2001 From: martin4861 Date: Fri, 6 Feb 2026 11:06:17 +0100 Subject: [PATCH 3/9] Add tests for marker and marker+extra --- tests/tools/wheelmaker_test.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/tools/wheelmaker_test.py b/tests/tools/wheelmaker_test.py index a2d4c951dd..85094af9b8 100644 --- a/tests/tools/wheelmaker_test.py +++ b/tests/tools/wheelmaker_test.py @@ -89,6 +89,23 @@ def test_requirement_with_url(self): "Requires-Dist: requests @ git+https://github.com/psf/requests.git@3aa6386c3", ) + def test_requirement_with_marker(self): + result = wheelmaker.get_new_requirement_line( + "requests>=2.0; python_version>='3.6'", "" + ) + self.assertEqual( + result, 'Requires-Dist: requests>=2.0; python_version >= "3.6"' + ) + + def test_requirement_with_marker_and_extra(self): + result = wheelmaker.get_new_requirement_line( + "requests>=2.0; python_version>='3.6'", "extra=='dev'" + ) + self.assertEqual( + result, + "Requires-Dist: requests>=2.0; (python_version >= \"3.6\") and extra=='dev'", + ) + if __name__ == "__main__": unittest.main() From b188f63814ee7ec6b53625e1d1614fa05aae0bb1 Mon Sep 17 00:00:00 2001 From: martin4861 Date: Fri, 6 Feb 2026 08:52:48 +0100 Subject: [PATCH 4/9] Implement url handling for requirements --- tools/wheelmaker.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tools/wheelmaker.py b/tools/wheelmaker.py index 72a6ab2434..6c43a1d84d 100644 --- a/tools/wheelmaker.py +++ b/tools/wheelmaker.py @@ -368,16 +368,21 @@ def get_new_requirement_line(reqs_text, extra): req = Requirement(reqs_text.strip()) req_extra_deps = f"[{','.join(req.extras)}]" if req.extras else "" + + # Handle URL requirements (PEP 508) + if req.url: + req_spec = f" @ {req.url}" + else: + req_spec = str(req.specifier) + if req.marker: if extra: - return f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; ({req.marker}) and {extra}" + return f"Requires-Dist: {req.name}{req_extra_deps}{req_spec}; ({req.marker}) and {extra}" else: - return f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; {req.marker}" + return f"Requires-Dist: {req.name}{req_extra_deps}{req_spec}; {req.marker}" else: - return ( - f"Requires-Dist: {req.name}{req_extra_deps}{req.specifier}; {extra}".strip( - " ;" - ) + return f"Requires-Dist: {req.name}{req_extra_deps}{req_spec}; {extra}".strip( + " ;" ) From 1b61d7e04d2d3db8f3748134711c533e2d92dab1 Mon Sep 17 00:00:00 2001 From: martin4861 Date: Fri, 6 Feb 2026 08:54:43 +0100 Subject: [PATCH 5/9] Add docstring --- tools/wheelmaker.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/wheelmaker.py b/tools/wheelmaker.py index 6c43a1d84d..20e2efadc7 100644 --- a/tools/wheelmaker.py +++ b/tools/wheelmaker.py @@ -364,6 +364,7 @@ def get_files_to_package(input_files): def get_new_requirement_line(reqs_text, extra): + """Formats a requirement text into a Requires-Dist metadata line.""" from packaging.requirements import Requirement req = Requirement(reqs_text.strip()) From 50eaf2b15410e735459c8a774f1fd0064818f0d6 Mon Sep 17 00:00:00 2001 From: martin4861 Date: Fri, 6 Feb 2026 11:08:03 +0100 Subject: [PATCH 6/9] Reduce code duplication --- tools/wheelmaker.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/wheelmaker.py b/tools/wheelmaker.py index 20e2efadc7..b4151022b8 100644 --- a/tools/wheelmaker.py +++ b/tools/wheelmaker.py @@ -376,15 +376,17 @@ def get_new_requirement_line(reqs_text, extra): else: req_spec = str(req.specifier) + base = f"Requires-Dist: {req.name}{req_extra_deps}{req_spec}" + if req.marker: if extra: - return f"Requires-Dist: {req.name}{req_extra_deps}{req_spec}; ({req.marker}) and {extra}" + return f"{base}; ({req.marker}) and {extra}" else: - return f"Requires-Dist: {req.name}{req_extra_deps}{req_spec}; {req.marker}" + return f"{base}; {req.marker}" + elif extra: + return f"{base}; {extra}" else: - return f"Requires-Dist: {req.name}{req_extra_deps}{req_spec}; {extra}".strip( - " ;" - ) + return base def resolve_argument_stamp( From 1d215878f62e48df4c0762b4eff92b2c567624d1 Mon Sep 17 00:00:00 2001 From: martin4861 Date: Fri, 6 Feb 2026 11:33:06 +0100 Subject: [PATCH 7/9] Add type annotations --- tools/wheelmaker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/wheelmaker.py b/tools/wheelmaker.py index b4151022b8..7124ae7c9d 100644 --- a/tools/wheelmaker.py +++ b/tools/wheelmaker.py @@ -363,7 +363,7 @@ def get_files_to_package(input_files): return files -def get_new_requirement_line(reqs_text, extra): +def get_new_requirement_line(reqs_text: str, extra: str) -> str: """Formats a requirement text into a Requires-Dist metadata line.""" from packaging.requirements import Requirement From a6bff79650f56a2526cd7e0e20eee74da27cbca3 Mon Sep 17 00:00:00 2001 From: martin4861 Date: Mon, 9 Feb 2026 07:11:46 +0100 Subject: [PATCH 8/9] Update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15118f53e9..be608189c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,6 +102,8 @@ END_UNRELEASED_TEMPLATE {obj}`PyExecutableInfo.interpreter_args`, {obj}`PyExecutableInfo.stage2_bootstrap`, and {obj}`PyExecutableInfo.venv_python_exe`. +* (tools/wheelmaker.py) Added support for URL requirements according to PEP 508 + in Requires-Dist metadata. {#v1-8-3} ## [1.8.3] - 2026-01-27 From 07388dcea0a7ad5aa930666d41dd06c6e981b14b Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius <240938+aignas@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:44:31 +0900 Subject: [PATCH 9/9] Apply suggestion from @aignas --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be608189c3..96e7dcd5b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,7 +103,7 @@ END_UNRELEASED_TEMPLATE {obj}`PyExecutableInfo.stage2_bootstrap`, and {obj}`PyExecutableInfo.venv_python_exe`. * (tools/wheelmaker.py) Added support for URL requirements according to PEP 508 - in Requires-Dist metadata. + in Requires-Dist metadata. ([#3569](https://github.com/bazel-contrib/rules_python/pull/3569)) {#v1-8-3} ## [1.8.3] - 2026-01-27