Skip to content

Commit b252cd8

Browse files
committed
Emit chunks of lines instead of individual lines
This should allow us to get smaller diff chunks from Black than by diffing and analyzing Black's string output for whole files.
1 parent 66add27 commit b252cd8

File tree

4 files changed

+35
-32
lines changed

4 files changed

+35
-32
lines changed

src/darker/black_diff.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@
4949
from black.const import DEFAULT_EXCLUDES, DEFAULT_INCLUDES
5050
from black.files import gen_python_files
5151
from black.report import Report
52-
from darker.linewise_black import format_str_to_lines
5352

53+
from darker.linewise_black import format_str_to_chunks
5454
from darker.utils import TextDocument
5555

5656
if sys.version_info >= (3, 8):
@@ -181,8 +181,8 @@ def run_black(src_contents: TextDocument, black_config: BlackConfig) -> TextDocu
181181
# https://github.com/psf/black/pull/2484 lands in Black.
182182
contents_for_black = src_contents.string_with_newline("\n")
183183
if contents_for_black.strip():
184-
dst_lines = format_str_to_lines(contents_for_black, mode=Mode(**mode))
185-
dst_contents = "".join(dst_lines)
184+
dst_chunks = format_str_to_chunks(contents_for_black, mode=Mode(**mode))
185+
dst_contents = "".join(line for chunk in dst_chunks for line in chunk)
186186
else:
187187
dst_contents = "\n" if "\n" in src_contents.string else ""
188188
return TextDocument.from_str(

src/darker/linewise_black.py

+25-22
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
"""Re-implementation of :func:`black.format_str` as a line generator"""
22

3-
from typing import Generator
4-
from black import get_future_imports, detect_target_versions, decode_bytes
5-
from black.lines import Line, EmptyLineTracker
6-
from black.linegen import transform_line, LineGenerator
3+
from typing import Generator, List
4+
5+
from black import decode_bytes, detect_target_versions, get_future_imports
76
from black.comments import normalize_fmt_off
8-
from black.mode import Mode
9-
from black.mode import Feature, supports_feature
7+
from black.linegen import LineGenerator, transform_line
8+
from black.lines import EmptyLineTracker, Line
9+
from black.mode import Feature, Mode, supports_feature
1010
from black.parsing import lib2to3_parse
1111

1212

13-
def format_str_to_lines(
13+
def format_str_to_chunks( # pylint: disable=too-many-locals
1414
src_contents: str, *, mode: Mode
15-
) -> Generator[str, None, None]: # pylint: disable=too-many-locals
15+
) -> Generator[List[str], None, None]:
1616
"""Reformat a string and yield each line of new contents
1717
1818
This is a re-implementation of :func:`black.format_str` modified to be a generator
19-
which yields each resulting line instead of concatenating them into a single string.
19+
which yields each resulting chunk as a list of lines instead of concatenating them
20+
into a single string.
2021
2122
"""
2223
src_node = lib2to3_parse(src_contents.lstrip(), mode.target_versions)
@@ -42,20 +43,22 @@ def format_str_to_lines(
4243
}
4344
num_chars = 0
4445
for current_line in lines.visit(src_node):
45-
for _ in range(after):
46-
yield empty_line
47-
num_chars += after * empty_line_len
46+
if after:
47+
yield after * [empty_line]
48+
num_chars += after * empty_line_len
4849
before, after = elt.maybe_empty_lines(current_line)
49-
for _ in range(before):
50-
yield empty_line
51-
num_chars += before * empty_line_len
52-
for line in transform_line(
53-
current_line, mode=mode, features=split_line_features
54-
):
55-
line_str = str(line)
56-
yield line_str
57-
num_chars += len(line_str)
50+
if before:
51+
yield before * [empty_line]
52+
num_chars += before * empty_line_len
53+
lines = [
54+
str(line)
55+
for line in transform_line(
56+
current_line, mode=mode, features=split_line_features
57+
)
58+
]
59+
yield lines
60+
num_chars += sum(len(line) for line in lines)
5861
if not num_chars:
5962
normalized_content, _, newline = decode_bytes(src_contents.encode("utf-8"))
6063
if "\n" in normalized_content:
61-
yield newline
64+
yield [newline]

src/darker/tests/test_black_diff.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,12 @@ def test_run_black(encoding, newline):
196196
def test_run_black_always_uses_unix_newlines(newline):
197197
"""Content is always passed to Black with Unix newlines"""
198198
src = TextDocument.from_str(f"print ( 'touché' ){newline}")
199-
with patch.object(black_diff, "format_str_to_lines") as format_str_to_lines:
200-
format_str_to_lines.return_value = ['print("touché")\n']
199+
with patch.object(black_diff, "format_str_to_chunks") as format_str_to_chunks:
200+
format_str_to_chunks.return_value = [['print("touché")\n']]
201201

202202
_ = run_black(src, BlackConfig())
203203

204-
format_str_to_lines.assert_called_once_with("print ( 'touché' )\n", mode=ANY)
204+
format_str_to_chunks.assert_called_once_with("print ( 'touché' )\n", mode=ANY)
205205

206206

207207
def test_run_black_ignores_excludes():

src/darker/tests/test_command_line.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -470,9 +470,9 @@ def test_black_options_skip_string_normalization(git_repo, config, options, expe
470470
added_files["main.py"].write_bytes(b"bar")
471471
mode_class_mock = Mock(wraps=black_diff.Mode)
472472
# Speed up tests by mocking `format_str` to skip running Black
473-
format_str_to_lines = Mock(return_value=["bar"])
473+
format_str_to_chunks = Mock(return_value=[["bar"]])
474474
with patch.multiple(
475-
black_diff, Mode=mode_class_mock, format_str_to_lines=format_str_to_lines
475+
black_diff, Mode=mode_class_mock, format_str_to_chunks=format_str_to_chunks
476476
):
477477

478478
main(options + [str(path) for path in added_files.values()])
@@ -498,9 +498,9 @@ def test_black_options_skip_magic_trailing_comma(git_repo, config, options, expe
498498
added_files["main.py"].write_bytes(b"a = [1, 2,]")
499499
mode_class_mock = Mock(wraps=black_diff.Mode)
500500
# Speed up tests by mocking `format_str` to skip running Black
501-
format_str_to_lines = Mock(return_value=["a = [1, 2,]"])
501+
format_str_to_chunks = Mock(return_value=[["a = [1, 2,]"]])
502502
with patch.multiple(
503-
black_diff, Mode=mode_class_mock, format_str_to_lines=format_str_to_lines
503+
black_diff, Mode=mode_class_mock, format_str_to_chunks=format_str_to_chunks
504504
):
505505

506506
main(options + [str(path) for path in added_files.values()])

0 commit comments

Comments
 (0)