Skip to content

Commit

Permalink
Fix --line-ranges behavior when ranges are at EOF (#4273)
Browse files Browse the repository at this point in the history
Fixes #4264
  • Loading branch information
sumezulike authored Mar 15, 2024
1 parent 1abcffc commit 7b5a657
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
of Black would incorrectly format the contents of certain unusual f-strings containing
nested strings with the same quote type. Now, Black will crash on such strings until
support for the new f-string syntax is implemented. (#4270)
- Fixed a bug where line-ranges exceeding the last code line would not work as expected
(#4273)

### Preview style

Expand Down
11 changes: 10 additions & 1 deletion src/black/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,12 @@
parse_ast,
stringify_ast,
)
from black.ranges import adjusted_lines, convert_unchanged_lines, parse_line_ranges
from black.ranges import (
adjusted_lines,
convert_unchanged_lines,
parse_line_ranges,
sanitized_lines,
)
from black.report import Changed, NothingChanged, Report
from black.trans import iter_fexpr_spans
from blib2to3.pgen2 import token
Expand Down Expand Up @@ -1220,6 +1225,10 @@ def f(
hey
"""
if lines:
lines = sanitized_lines(lines, src_contents)
if not lines:
return src_contents # Nothing to format
dst_contents = _format_str_once(src_contents, mode=mode, lines=lines)
# Forced second pass to work around optional trailing commas (becoming
# forced trailing commas on pass 2) interacting differently with optional
Expand Down
28 changes: 28 additions & 0 deletions src/black/ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,34 @@ def is_valid_line_range(lines: Tuple[int, int]) -> bool:
return not lines or lines[0] <= lines[1]


def sanitized_lines(
lines: Collection[Tuple[int, int]], src_contents: str
) -> Collection[Tuple[int, int]]:
"""Returns the valid line ranges for the given source.
This removes ranges that are entirely outside the valid lines.
Other ranges are normalized so that the start values are at least 1 and the
end values are at most the (1-based) index of the last source line.
"""
if not src_contents:
return []
good_lines = []
src_line_count = src_contents.count("\n")
if not src_contents.endswith("\n"):
src_line_count += 1
for start, end in lines:
if start > src_line_count:
continue
# line-ranges are 1-based
start = max(start, 1)
if end < start:
continue
end = min(end, src_line_count)
good_lines.append((start, end))
return good_lines


def adjusted_lines(
lines: Collection[Tuple[int, int]],
original_source: str,
Expand Down
36 changes: 36 additions & 0 deletions tests/data/cases/line_ranges_exceeding_end.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# flags: --line-ranges=6-1000
# NOTE: If you need to modify this file, pay special attention to the --line-ranges=
# flag above as it's formatting specifically these lines.
def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
def foo2(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
def foo3(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
def foo4(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass

# output
# flags: --line-ranges=6-1000
# NOTE: If you need to modify this file, pay special attention to the --line-ranges=
# flag above as it's formatting specifically these lines.
def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
def foo2(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
def foo3(
parameter_1,
parameter_2,
parameter_3,
parameter_4,
parameter_5,
parameter_6,
parameter_7,
):
pass


def foo4(
parameter_1,
parameter_2,
parameter_3,
parameter_4,
parameter_5,
parameter_6,
parameter_7,
):
pass
7 changes: 7 additions & 0 deletions tests/data/cases/line_ranges_outside_source.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# flags: --line-ranges=5000-6000
# NOTE: If you need to modify this file, pay special attention to the --line-ranges=
# flag above as it's formatting specifically these lines, in this case none.
def foo1(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
def foo2(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
def foo3(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
def foo4(parameter_1, parameter_2, parameter_3, parameter_4, parameter_5, parameter_6, parameter_7): pass
66 changes: 65 additions & 1 deletion tests/test_ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from black.ranges import adjusted_lines
from black.ranges import adjusted_lines, sanitized_lines


@pytest.mark.parametrize(
Expand Down Expand Up @@ -183,3 +183,67 @@ def test_diffs(lines: List[Tuple[int, int]], adjusted: List[Tuple[int, int]]) ->
12. # last line changed
"""
assert adjusted == adjusted_lines(lines, original_source, modified_source)


@pytest.mark.parametrize(
"lines,sanitized",
[
(
[(1, 4)],
[(1, 4)],
),
(
[(2, 3)],
[(2, 3)],
),
(
[(2, 10)],
[(2, 4)],
),
(
[(0, 3)],
[(1, 3)],
),
(
[(0, 10)],
[(1, 4)],
),
(
[(-2, 3)],
[(1, 3)],
),
(
[(0, 0)],
[],
),
(
[(-2, -1)],
[],
),
(
[(-1, 0)],
[],
),
(
[(3, 1), (1, 3), (5, 6)],
[(1, 3)],
),
],
)
def test_sanitize(
lines: List[Tuple[int, int]], sanitized: List[Tuple[int, int]]
) -> None:
source = """\
1. import re
2. def func(arg1,
3. arg2, arg3):
4. pass
"""
assert sanitized == sanitized_lines(lines, source)

source_no_trailing_nl = """\
1. import re
2. def func(arg1,
3. arg2, arg3):
4. pass"""
assert sanitized == sanitized_lines(lines, source_no_trailing_nl)

0 comments on commit 7b5a657

Please sign in to comment.