Skip to content

Commit

Permalink
Improve formatting of long "via" annotations
Browse files Browse the repository at this point in the history
When there is more than one "via" annotation, they are now formatted one
per line. This prevents very long lines in requirements.txt output. The
very long lines often scroll beyond the width of an editor, making them
difficult to read. Worse, when these annotations change, diffs are hard
to read as the actual difference is hidden far off to the right. By
placing one annotation per line, diffs will be much more obvious. This
follows the philosophy of many automatic formatters such as Black.

To simplify the formatting and to make it more consistent, annotations
are now always on the line after the requirement, whether hashes were
generated or not.

Fixes #1036
  • Loading branch information
jdufresne committed Nov 26, 2020
1 parent 09b6855 commit 79bc8c6
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 10 deletions.
8 changes: 6 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 10 additions & 2 deletions piptools/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
59 changes: 58 additions & 1 deletion tests/test_cli_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down
10 changes: 5 additions & 5 deletions tests/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,37 +53,37 @@ 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):
"Primary packages should get annotated."
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):
"Primary packages should get annotated."
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):
Expand Down

0 comments on commit 79bc8c6

Please sign in to comment.