Skip to content

Commit d247f43

Browse files
AndydeCleyrewebknjaz
authored andcommitted
Replace newline choices with --force-lf-newlines flag
The default behavior remains identical to what was --newline=preserve.
1 parent 6dad09d commit d247f43

File tree

2 files changed

+43
-70
lines changed

2 files changed

+43
-70
lines changed

piptools/scripts/compile.py

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,33 +49,24 @@ def _get_default_option(option_name: str) -> Any:
4949
return getattr(default_values, option_name)
5050

5151

52-
def _determine_linesep(
53-
strategy: str = "preserve", filenames: Tuple[str, ...] = ()
54-
) -> str:
52+
def _existing_linesep(*filenames: str) -> str:
5553
"""
56-
Determine and return linesep string for OutputWriter to use.
57-
Valid strategies: "LF", "CRLF", "native", "preserve"
58-
When preserving, files are checked in order for existing newlines.
54+
Check files in order for an existing linesep and return it, if possible.
55+
Otherwise, return LF ("\n").
5956
"""
60-
if strategy == "preserve":
61-
for fname in filenames:
62-
try:
63-
with open(fname, "rb") as existing_file:
64-
existing_text = existing_file.read()
65-
except FileNotFoundError:
66-
continue
67-
if b"\r\n" in existing_text:
68-
strategy = "CRLF"
69-
break
70-
elif b"\n" in existing_text:
71-
strategy = "LF"
72-
break
73-
return {
74-
"native": os.linesep,
75-
"LF": "\n",
76-
"CRLF": "\r\n",
77-
"preserve": "\n",
78-
}[strategy]
57+
linesep = "\n"
58+
for fname in filenames:
59+
try:
60+
with open(fname, "rb") as existing_file:
61+
existing_text = existing_file.read()
62+
except FileNotFoundError:
63+
continue
64+
if b"\r\n" in existing_text:
65+
linesep = "\r\n"
66+
break
67+
elif b"\n" in existing_text:
68+
break
69+
return linesep
7970

8071

8172
@click.command(context_settings={"help_option_names": ("-h", "--help")})
@@ -195,10 +186,10 @@ def _determine_linesep(
195186
),
196187
)
197188
@click.option(
198-
"--newline",
199-
type=click.Choice(("LF", "CRLF", "native", "preserve"), case_sensitive=False),
200-
default="preserve",
201-
help="Override the newline control characters used",
189+
"--force-lf-newlines",
190+
is_flag=True,
191+
default=False,
192+
help="Always use LF newlines, rather than auto-detecting from existing files.",
202193
)
203194
@click.option(
204195
"--allow-unsafe/--no-allow-unsafe",
@@ -314,7 +305,7 @@ def cli(
314305
upgrade: bool,
315306
upgrade_packages: Tuple[str, ...],
316307
output_file: Union[LazyFile, IO[Any], None],
317-
newline: str,
308+
force_lf_newlines: bool,
318309
allow_unsafe: bool,
319310
strip_extras: bool,
320311
generate_hashes: bool,
@@ -551,8 +542,8 @@ def cli(
551542

552543
log.debug("")
553544

554-
linesep = _determine_linesep(
555-
strategy=newline, filenames=(output_file.name, *src_files)
545+
linesep = (
546+
"\n" if force_lf_newlines else _existing_linesep(output_file.name, *src_files)
556547
)
557548

558549
##

tests/test_cli_compile.py

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -946,23 +946,8 @@ def test_generate_hashes_with_annotations(runner):
946946
("--annotation-style", "split"),
947947
),
948948
)
949-
@pytest.mark.parametrize(
950-
("nl_options", "must_include", "must_exclude"),
951-
(
952-
pytest.param(("--newline", "lf"), "\n", "\r\n", id="LF"),
953-
pytest.param(("--newline", "crlf"), "\r\n", "\n", id="CRLF"),
954-
pytest.param(
955-
("--newline", "native"),
956-
os.linesep,
957-
{"\n": "\r\n", "\r\n": "\n"}[os.linesep],
958-
id="native",
959-
),
960-
),
961-
)
962-
def test_override_newline(
963-
runner, gen_hashes, annotate_options, nl_options, must_include, must_exclude
964-
):
965-
opts = annotate_options + nl_options
949+
def test_force_lf_newlines(runner, gen_hashes, annotate_options):
950+
opts = (*annotate_options, "--force-lf-newlines")
966951
if gen_hashes:
967952
opts += ("--generate-hashes",)
968953

@@ -975,39 +960,36 @@ def test_override_newline(
975960
with open("requirements.txt", "rb") as req_txt:
976961
txt = req_txt.read().decode()
977962

978-
assert must_include in txt
963+
assert "\n" in txt
964+
assert "\r\n" not in txt
979965

980-
if must_exclude in must_include:
981-
txt = txt.replace(must_include, "")
982-
assert must_exclude not in txt
983-
984-
# Do it again, with --newline=preserve:
985966

986-
opts = annotate_options + ("--newline", "preserve")
987-
if gen_hashes:
988-
opts += ("--generate-hashes",)
967+
@pytest.mark.network
968+
@pytest.mark.parametrize(
969+
("linesep", "must_exclude"),
970+
(pytest.param("\n", "\r\n", id="LF"), pytest.param("\r\n", "\n", id="CRLF")),
971+
)
972+
def test_preserve_newlines_from_output_or_input(runner, linesep, must_exclude):
973+
with open("requirements.in", "wb") as req_in:
974+
req_in.write(f"six{linesep}".encode())
989975

990-
runner.invoke(cli, [*opts, "requirements.in"])
976+
runner.invoke(cli, ["requirements.in"])
991977
with open("requirements.txt", "rb") as req_txt:
992978
txt = req_txt.read().decode()
993979

994-
assert must_include in txt
980+
assert linesep in txt
995981

996-
if must_exclude in must_include:
997-
txt = txt.replace(must_include, "")
982+
if must_exclude in linesep:
983+
txt = txt.replace(linesep, "")
998984
assert must_exclude not in txt
999985

986+
# Now that we have good output,
987+
# see that it's preserved when we have bad input:
1000988

1001-
@pytest.mark.network
1002-
@pytest.mark.parametrize(
1003-
("linesep", "must_exclude"),
1004-
(pytest.param("\n", "\r\n", id="LF"), pytest.param("\r\n", "\n", id="CRLF")),
1005-
)
1006-
def test_preserve_newline_from_input(runner, linesep, must_exclude):
1007989
with open("requirements.in", "wb") as req_in:
1008-
req_in.write(f"six{linesep}".encode())
990+
req_in.write(f"six{must_exclude}".encode())
1009991

1010-
runner.invoke(cli, ["--newline=preserve", "requirements.in"])
992+
runner.invoke(cli, ["requirements.in"])
1011993
with open("requirements.txt", "rb") as req_txt:
1012994
txt = req_txt.read().decode()
1013995

0 commit comments

Comments
 (0)