From a8609e51e2b4e1f935dacd1cb7ffbc386a24cb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Prpi=C4=8D?= Date: Tue, 15 Sep 2026 15:30:13 -0400 Subject: [PATCH] fix(dependencies): sort requirements files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `_write_requirements_file()` wrote requirement sets in iteration order so rebuilds of identical sources could produced different files even though the content was the same. Co-authored-by: Claude Opus 4.8 Signed-off-by: Martin Prpič --- src/fromager/dependencies.py | 2 +- tests/test_dependencies.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/fromager/dependencies.py b/src/fromager/dependencies.py index d80899e8..18dcdbef 100644 --- a/src/fromager/dependencies.py +++ b/src/fromager/dependencies.py @@ -574,7 +574,7 @@ def _write_requirements_file( filename: pathlib.Path, ) -> None: with open(filename, "w") as f: - for r in requirements: + for r in sorted(requirements, key=str): f.write(f"{r}\n") diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index 6f83a93e..34a68ee8 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -179,6 +179,20 @@ def test_get_build_system_dependencies_cached( assert results == set([Requirement("foo==1.0")]) +def test_write_requirements_file_sorted(tmp_path: pathlib.Path) -> None: + """Verify the file content does not depend on input or set order.""" + req_file = tmp_path / "build-system-requirements.txt" + requirements = [ + Requirement("setuptools>=42"), + Requirement("setuptools-scm[toml]>=3.4"), + Requirement("cython"), + ] + dependencies._write_requirements_file(requirements, req_file) + assert req_file.read_text() == ( + "cython\nsetuptools-scm[toml]>=3.4\nsetuptools>=42\n" + ) + + @patch("fromager.dependencies._write_requirements_file") @_clean_build_artifacts @pytest.mark.network