Skip to content

Commit 14cc0e4

Browse files
committed
Preserve crlf line endings in blackd
1 parent 383b228 commit 14cc0e4

File tree

5 files changed

+37
-1
lines changed

5 files changed

+37
-1
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
### _Blackd_
3838

39-
<!-- Changes to blackd -->
39+
- Windows style (CRLF) newlines will be preserved (#3257).
4040

4141
### Integrations
4242

docs/the_black_code_style/current_style.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ file that are not enforced yet but might be in a future version of the formatter
406406
- use variable annotations instead of type comments, even for stubs that target older
407407
versions of Python.
408408

409+
### Line endings
410+
_Black_ will normalize line endings (`\n` or `\r\n`) based on the first line ending of
411+
the file.
412+
409413
## Pragmatism
410414

411415
Early versions of _Black_ used to be absolutist in some respects. They took after its

src/blackd/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ async def handle(request: web.Request, executor: Executor) -> web.Response:
133133
executor, partial(black.format_file_contents, req_str, fast=fast, mode=mode)
134134
)
135135

136+
# Preserve CRLF line endings
137+
if req_str[req_str.find("\n") - 1] == "\r":
138+
formatted_str = formatted_str.replace("\n", "\r\n")
139+
# If, after swapping line endings, nothing changed, then say so
140+
if formatted_str == req_str:
141+
raise black.NothingChanged
142+
136143
# Only output the diff in the HTTP response
137144
only_diff = bool(request.headers.get(DIFF_HEADER, False))
138145
if only_diff:

tests/test_black.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,14 @@ def test_preserves_line_endings_via_stdin(self) -> None:
12861286
if nl == "\n":
12871287
self.assertNotIn(b"\r\n", output)
12881288

1289+
def test_normalize_line_endings(self) -> None:
1290+
with TemporaryDirectory() as workspace:
1291+
test_file = Path(workspace) / "test.py"
1292+
for data, expected in ((b"c\r\nc\n ", b"c\r\nc\r\n"), (b"l\nl\r\n ", b"l\nl\n")):
1293+
test_file.write_bytes(data)
1294+
ff(test_file, write_back=black.WriteBack.YES)
1295+
self.assertEqual(test_file.read_bytes(), expected)
1296+
12891297
def test_assert_equivalent_different_asts(self) -> None:
12901298
with self.assertRaises(AssertionError):
12911299
black.assert_equivalent("{}", "None")

tests/test_blackd.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,20 @@ async def test_cors_headers_present(self) -> None:
209209
response = await self.client.post("/", headers={"Origin": "*"})
210210
self.assertIsNotNone(response.headers.get("Access-Control-Allow-Origin"))
211211
self.assertIsNotNone(response.headers.get("Access-Control-Expose-Headers"))
212+
213+
@unittest_run_loop
214+
async def test_preserves_line_endings(self) -> None:
215+
for data in (b"c\r\nc\r\n", b"l\nl\n"):
216+
# test preserved newlines when reformatted
217+
response = await self.client.post("/", data=data + b" ")
218+
self.assertEqual(await response.text(), data.decode())
219+
# test 204 when no change
220+
response = await self.client.post("/", data=data)
221+
self.assertEqual(response.status, 204)
222+
223+
@unittest_run_loop
224+
async def test_normalizes_line_endings(self) -> None:
225+
for data, expected in ((b"c\r\nc\n", "c\r\nc\r\n"), (b"l\nl\r\n", "l\nl\n")):
226+
response = await self.client.post("/", data=data)
227+
self.assertEqual(await response.text(), expected)
228+
self.assertEqual(response.status, 200)

0 commit comments

Comments
 (0)