From a105469fc660627db18a7704724946f02b2a479b Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Tue, 30 Apr 2024 10:26:03 -0500 Subject: [PATCH 1/4] Order format controls to preserve behavior in pip --- piptools/writer.py | 22 ++++++++++++++++++++-- tests/test_writer.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/piptools/writer.py b/piptools/writer.py index bcb70f02f..da603f1f7 100644 --- a/piptools/writer.py +++ b/piptools/writer.py @@ -148,9 +148,27 @@ def write_trusted_hosts(self) -> Iterator[str]: yield f"--trusted-host {trusted_host}" def write_format_controls(self) -> Iterator[str]: - for nb in dedup(sorted(self.format_control.no_binary)): + # The ordering of output needs to preserve the behavior of pip's + # FormatControl.get_allowed_formats(). The behavior is the following: + # + # * Parsing of CLI options happens first to last. + # * --only-binary takes precedence over --no-binary + # * Package names take precedence over :all: + # * We'll never see :all: in both due to mutual exclusion. + # + # So in summary, we want to emit :all: first and then package names later. + no_binary = self.format_control.no_binary.copy() + only_binary = self.format_control.only_binary.copy() + + if ":all:" in no_binary: + yield "--no-binary :all:" + no_binary.remove(":all:") + if ":all:" in only_binary: + yield "--only-binary :all:" + only_binary.remove(":all:") + for nb in dedup(sorted(no_binary)): yield f"--no-binary {nb}" - for ob in dedup(sorted(self.format_control.only_binary)): + for ob in dedup(sorted(only_binary)): yield f"--only-binary {ob}" def write_find_links(self) -> Iterator[str]: diff --git a/tests/test_writer.py b/tests/test_writer.py index 8a59269c7..a10e23bdc 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -301,6 +301,37 @@ def test_write_format_controls(writer): assert lines == expected_lines +def test_write_format_controls_all(writer): + """ + Tests --no-binary/--only-binary options + with the value of :all: + """ + + # We want to preserve the FormatControl behavior + # so we emit :all: first before packages. + writer.format_control = FormatControl( + no_binary=[":all:"], only_binary=["django"] + ) + lines = list(writer.write_format_controls()) + + expected_lines = [ + "--no-binary :all:", + "--only-binary django", + ] + assert lines == expected_lines + + writer.format_control = FormatControl( + no_binary=["django"], only_binary=[":all:"] + ) + lines = list(writer.write_format_controls()) + + expected_lines = [ + "--only-binary :all:", + "--no-binary django", + ] + assert lines == expected_lines + + @pytest.mark.parametrize( ("index_urls", "expected_lines"), ( From 19d3cc7672682b56defc75348b5dc09cd8415fe0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:27:15 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_writer.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/test_writer.py b/tests/test_writer.py index a10e23bdc..b31e35847 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -309,9 +309,7 @@ def test_write_format_controls_all(writer): # We want to preserve the FormatControl behavior # so we emit :all: first before packages. - writer.format_control = FormatControl( - no_binary=[":all:"], only_binary=["django"] - ) + writer.format_control = FormatControl(no_binary=[":all:"], only_binary=["django"]) lines = list(writer.write_format_controls()) expected_lines = [ @@ -320,9 +318,7 @@ def test_write_format_controls_all(writer): ] assert lines == expected_lines - writer.format_control = FormatControl( - no_binary=["django"], only_binary=[":all:"] - ) + writer.format_control = FormatControl(no_binary=["django"], only_binary=[":all:"]) lines = list(writer.write_format_controls()) expected_lines = [ From 8e6dd76af89cc3081e4522d8de1095379f6f3e8c Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Tue, 30 Apr 2024 10:44:35 -0500 Subject: [PATCH 3/4] Restructure test to use pytest parametrization --- tests/test_writer.py | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/tests/test_writer.py b/tests/test_writer.py index b31e35847..6d8d1e5c7 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -301,30 +301,38 @@ def test_write_format_controls(writer): assert lines == expected_lines -def test_write_format_controls_all(writer): +@pytest.mark.parametrize( + ["no_binary", "only_binary", "expected_lines"], + [ + ( + [":all:"], + ["django"], + [ + "--no-binary :all:", + "--only-binary django", + ], + ), + ( + ["django"], + [":all:"], + [ + "--only-binary :all:", + "--no-binary django", + ], + ), + ], +) +def test_write_format_controls_all(writer, no_binary, only_binary, expected_lines): """ Tests --no-binary/--only-binary options - with the value of :all: + with the value of :all:. We want to preserve + the FormatControl behavior so we emit :all: + first before packages. """ - # We want to preserve the FormatControl behavior - # so we emit :all: first before packages. - writer.format_control = FormatControl(no_binary=[":all:"], only_binary=["django"]) - lines = list(writer.write_format_controls()) - - expected_lines = [ - "--no-binary :all:", - "--only-binary django", - ] - assert lines == expected_lines - - writer.format_control = FormatControl(no_binary=["django"], only_binary=[":all:"]) + writer.format_control = FormatControl(no_binary=no_binary, only_binary=only_binary) lines = list(writer.write_format_controls()) - expected_lines = [ - "--only-binary :all:", - "--no-binary django", - ] assert lines == expected_lines From d4d5fd42f0c0ed7aaa186720594d0e7c2ab31aaf Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Tue, 30 Apr 2024 11:35:46 -0500 Subject: [PATCH 4/4] Change to tuples for pytest parametrize --- tests/test_writer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_writer.py b/tests/test_writer.py index 6d8d1e5c7..dd4354485 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -302,8 +302,8 @@ def test_write_format_controls(writer): @pytest.mark.parametrize( - ["no_binary", "only_binary", "expected_lines"], - [ + ("no_binary", "only_binary", "expected_lines"), + ( ( [":all:"], ["django"], @@ -320,7 +320,7 @@ def test_write_format_controls(writer): "--no-binary django", ], ), - ], + ), ) def test_write_format_controls_all(writer, no_binary, only_binary, expected_lines): """