diff --git a/README.rst b/README.rst index f84f304ad..69c790daf 100644 --- a/README.rst +++ b/README.rst @@ -300,9 +300,13 @@ a constraint: django-debug-toolbar==2.2 # via -r dev-requirements.in django==2.1.15 - # via -c requirements.txt, django-debug-toolbar + # via + # -c requirements.txt + # django-debug-toolbar pytz==2019.3 - # via -c requirements.txt, django + # via + # -c requirements.txt + # django sqlparse==0.3.0 # via django-debug-toolbar diff --git a/piptools/writer.py b/piptools/writer.py index 23d3445fa..515df198e 100644 --- a/piptools/writer.py +++ b/piptools/writer.py @@ -230,6 +230,14 @@ def _format_requirement(self, ireq, marker=None, hashes=None): elif ireq.comes_from: required_by.add(_comes_from_as_string(ireq)) if required_by: - annotation = ", ".join(sorted(required_by)) - line = "{}\n {}".format(line, comment("# via " + annotation)) + required_by = sorted(required_by) + if len(required_by) == 1: + source = required_by[0] + annotation = " # via " + source + else: + annotation_lines = [" # via"] + for source in required_by: + annotation_lines.append(" # " + source) + annotation = "\n".join(annotation_lines) + line = "{}\n{}".format(line, comment(annotation)) return line diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index f59774bd3..cca7ecbd6 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -768,6 +768,61 @@ def test_generate_hashes_with_annotations(runner): ) +@pytest.mark.network +def test_generate_hashes_with_long_annotations(runner): + with open("requirements.in", "w") as fp: + fp.write("django-debug-toolbar==1.11\n") + fp.write("django-storages==1.9.1\n") + fp.write("django-taggit==0.24.0\n") + fp.write("Django==1.11.29\n") + fp.write("pytz==2020.4\n") + fp.write("sqlparse==0.3.1\n") + + out = runner.invoke(cli, ["--generate-hashes"]) + assert out.stderr == dedent( + """\ + # + # This file is autogenerated by pip-compile + # To update, run: + # + # pip-compile --generate-hashes + # + django-debug-toolbar==1.11 \\ + --hash=sha256:89d75b60c65db363fb24688d977e5fbf0e73386c67acf562d278402a10fc3736 \\ + --hash=sha256:c2b0134119a624f4ac9398b44f8e28a01c7686ac350a12a74793f3dd57a9eea0 + # via -r requirements.in + django-storages==1.9.1 \\ + --hash=sha256:3103991c2ee8cef8a2ff096709973ffe7106183d211a79f22cf855f33533d924 \\ + --hash=sha256:a59e9923cbce7068792f75344ed7727021ee4ac20f227cf17297d0d03d141e91 + # via -r requirements.in + django-taggit==0.24.0 \\ + --hash=sha256:710b4d15ec1996550cc68a0abbc41903ca7d832540e52b1336e6858737e410d8 \\ + --hash=sha256:bb8f27684814cd1414b2af75b857b5e26a40912631904038a7ecacd2bfafc3ac + # via -r requirements.in + django==1.11.29 \\ + --hash=sha256:014e3392058d94f40569206a24523ce254d55ad2f9f46c6550b0fe2e4f94cf3f \\ + --hash=sha256:4200aefb6678019a0acf0005cd14cfce3a5e6b9b90d06145fcdd2e474ad4329c + # via + # -r requirements.in + # django-debug-toolbar + # django-storages + # django-taggit + pytz==2020.4 \\ + --hash=sha256:3e6b7dd2d1e0a59084bcee14a17af60c5c562cdc16d828e8eba2e683d3a7e268 \\ + --hash=sha256:5c55e189b682d420be27c6995ba6edce0c0a77dd67bfbe2ae6607134d5851ffd + # via + # -r requirements.in + # django + sqlparse==0.3.1 \\ + --hash=sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e \\ + --hash=sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548 + # via + # -r requirements.in + # django-debug-toolbar + """ + ) + + def test_filter_pip_markers(pip_conf, runner): """ Check that pip-compile works with pip environment markers (PEP496) @@ -911,7 +966,9 @@ def test_multiple_input_files_without_output_file(runner): # pip-compile --no-emit-find-links # small-fake-a==0.1 - # via -c constraints.txt, small-fake-with-deps + # via + # -c constraints.txt + # small-fake-with-deps small-fake-with-deps==0.1 # via -r requirements.in Dry-run, so nothing updated. diff --git a/tests/test_writer.py b/tests/test_writer.py index 2811c4eba..4abbdffcb 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -53,21 +53,21 @@ def test_format_requirement_annotation_editable(from_editable, writer): assert writer._format_requirement( ireq - ) == "-e git+git://fake.org/x/y.git#egg=y\n " + comment("# via xyz") + ) == "-e git+git://fake.org/x/y.git#egg=y\n" + comment(" # via xyz") def test_format_requirement_annotation(from_line, writer): ireq = from_line("test==1.2") ireq.comes_from = "xyz" - assert writer._format_requirement(ireq) == "test==1.2\n " + comment("# via xyz") + assert writer._format_requirement(ireq) == "test==1.2\n" + comment(" # via xyz") def test_format_requirement_annotation_lower_case(from_line, writer): ireq = from_line("Test==1.2") ireq.comes_from = "xyz" - assert writer._format_requirement(ireq) == "test==1.2\n " + comment("# via xyz") + assert writer._format_requirement(ireq) == "test==1.2\n" + comment(" # via xyz") def test_format_requirement_for_primary(from_line, writer): @@ -75,7 +75,7 @@ def test_format_requirement_for_primary(from_line, writer): ireq = from_line("test==1.2") ireq.comes_from = "xyz" - assert writer._format_requirement(ireq) == "test==1.2\n " + comment("# via xyz") + assert writer._format_requirement(ireq) == "test==1.2\n" + comment(" # via xyz") def test_format_requirement_for_primary_lower_case(from_line, writer): @@ -83,7 +83,7 @@ def test_format_requirement_for_primary_lower_case(from_line, writer): ireq = from_line("Test==1.2") ireq.comes_from = "xyz" - assert writer._format_requirement(ireq) == "test==1.2\n " + comment("# via xyz") + assert writer._format_requirement(ireq) == "test==1.2\n" + comment(" # via xyz") def test_format_requirement_environment_marker(from_line, writer):