Skip to content

Commit

Permalink
Empty and all-whitespace files become 1 empty line
Browse files Browse the repository at this point in the history
Fixes psf#2382
  • Loading branch information
Antti Kaihola committed Sep 9, 2021
1 parent 0f837d3 commit 5dee192
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 13 deletions.
10 changes: 6 additions & 4 deletions src/black/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ def format_stdin_to_stdout(
)
if write_back == WriteBack.YES:
# Make sure there's a newline after the content
if dst and dst[-1] != "\n":
if not dst or dst[-1] != "\n":
dst += "\n"
f.write(dst)
elif write_back in (WriteBack.DIFF, WriteBack.COLOR_DIFF):
Expand Down Expand Up @@ -889,9 +889,6 @@ def format_file_contents(src_contents: str, *, fast: bool, mode: Mode) -> FileCo
valid by calling :func:`assert_equivalent` and :func:`assert_stable` on it.
`mode` is passed to :func:`format_str`.
"""
if not src_contents.strip():
raise NothingChanged

if mode.is_ipynb:
dst_contents = format_ipynb_string(src_contents, fast=fast, mode=mode)
else:
Expand Down Expand Up @@ -979,6 +976,8 @@ def format_ipynb_string(src_contents: str, *, fast: bool, mode: Mode) -> FileCon
Operate cell-by-cell, only on code cells, only for Python notebooks.
If the ``.ipynb`` originally had a trailing newline, it'll be preserved.
"""
if not src_contents:
return ""
trailing_newline = src_contents[-1] == "\n"
modified = False
nb = json.loads(src_contents)
Expand Down Expand Up @@ -1061,6 +1060,9 @@ def f(
current_line, mode=mode, features=split_line_features
):
dst_contents.append(str(line))
if not dst_contents:
_, _, newline = decode_bytes(src_contents.encode("utf-8"))
return newline
return "".join(dst_contents)


Expand Down
6 changes: 6 additions & 0 deletions tests/data/whitespace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@





# output
45 changes: 36 additions & 9 deletions tests/test_black.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,39 @@ def invokeBlack(

@patch("black.dump_to_file", dump_to_stderr)
def test_empty(self) -> None:
source = expected = ""
source = ""
expected = "\n"
actual = fs(source)
self.assertFormatEqual(expected, actual)
black.assert_equivalent(source, actual)
black.assert_stable(source, actual, DEFAULT_MODE)

def test_empty_ff(self) -> None:
expected = ""
expected = "\n"
tmp_file = Path(black.dump_to_file())
try:
self.assertTrue(ff(tmp_file, write_back=black.WriteBack.YES))
with open(tmp_file, "rb") as f:
actual = f.read().decode("utf8")
finally:
os.unlink(tmp_file)
self.assertFormatEqual(expected, actual)

@patch("black.dump_to_file", dump_to_stderr)
def test_one_empty_line(self) -> None:
source = expected = os.linesep
actual = fs(source)
self.assertFormatEqual(expected, actual)
black.assert_equivalent(source, actual)
black.assert_stable(source, actual, DEFAULT_MODE)

def test_one_empty_line_ff(self) -> None:
expected = os.linesep
tmp_file = Path(black.dump_to_file("\n"))
try:
self.assertFalse(ff(tmp_file, write_back=black.WriteBack.YES))
with open(tmp_file, encoding="utf8") as f:
actual = f.read()
with open(tmp_file, "rb") as f:
actual = f.read().decode("utf8")
finally:
os.unlink(tmp_file)
self.assertFormatEqual(expected, actual)
Expand Down Expand Up @@ -990,11 +1010,17 @@ def err(msg: str, **kwargs: Any) -> None:
def test_format_file_contents(self) -> None:
empty = ""
mode = DEFAULT_MODE
with self.assertRaises(black.NothingChanged):
black.format_file_contents(empty, mode=mode, fast=False)
actual = black.format_file_contents(empty, mode=mode, fast=False)
self.assertEqual("\n", actual)
just_nl = "\n"
with self.assertRaises(black.NothingChanged):
black.format_file_contents(just_nl, mode=mode, fast=False)
just_whitespace_unix = "\n\t\n \n\t \n \t\n\n"
actual = black.format_file_contents(just_whitespace_unix, mode=mode, fast=False)
self.assertEqual("\n", actual)
just_whitespace_win = "\r\n\t\r\n \r\n\t \r\n \t\r\n\r\n"
actual = black.format_file_contents(just_whitespace_win, mode=mode, fast=False)
self.assertEqual("\r\n", actual)
same = "j = [1, 2, 3]\n"
with self.assertRaises(black.NothingChanged):
black.format_file_contents(same, mode=mode, fast=False)
Expand Down Expand Up @@ -1687,21 +1713,22 @@ def test_reformat_one_with_stdin_and_existing_path(self) -> None:
# __BLACK_STDIN_FILENAME__ should have been stripped
report.done.assert_called_with(expected, black.Changed.YES)

def test_reformat_one_with_stdin_empty(self) -> None:
@parameterized.expand([("", "\n"), (os.linesep, os.linesep)])
def test_reformat_one_with_stdin_empty(self, content, expected) -> None:
output = io.StringIO()
mock_io = Mock()
mock_io.TextIOWrapper.return_value = output
with patch.object(black, "io", mock_io):
try:
black.format_stdin_to_stdout(
fast=True,
content="",
content=content,
write_back=black.WriteBack.YES,
mode=DEFAULT_MODE,
)
except io.UnsupportedOperation:
pass # StringIO does not support detach
assert output.getvalue() == ""
assert output.getvalue() == expected

def test_gitignore_exclude(self) -> None:
path = THIS_DIR / "data" / "include_exclude_tests"
Expand Down
1 change: 1 addition & 0 deletions tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"string_prefixes",
"tricky_unicode_symbols",
"tupleassign",
"whitespace",
]

SIMPLE_CASES_PY2 = [
Expand Down

0 comments on commit 5dee192

Please sign in to comment.