Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context extension fix #20

Merged
merged 3 commits into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/darker/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@

logger = logging.getLogger(__name__)

# Maximum `git diff -U<context_lines> value to try with
MAX_CONTEXT_LINES = 1000


def format_edited_parts(
srcs: Iterable[Path],
Expand Down Expand Up @@ -72,16 +69,19 @@ def format_edited_parts(
edited_srcs = worktree_srcs

for src_relative, edited_content in edited_srcs.items():
for context_lines in range(MAX_CONTEXT_LINES + 1):
max_context_lines = len(edited_content)
for context_lines in range(max_context_lines + 1):
src = git_root / src_relative
edited = edited_content.splitlines()
head_lines = head_srcs[src_relative]

# 2. diff HEAD and worktree for all file & dir paths on the command line
# 2. diff HEAD and worktree for the file
edited_opcodes = diff_and_get_opcodes(head_lines, edited)

# 3. extract line numbers in each edited to-file for changed lines
edited_linenums = list(opcodes_to_edit_linenums(edited_opcodes))
edited_linenums = list(
opcodes_to_edit_linenums(edited_opcodes, context_lines)
)
if (
isort
and not edited_linenums
Expand Down Expand Up @@ -123,7 +123,7 @@ def format_edited_parts(
# a partially re-formatted Python file which produces an identical AST.
# Try again with a larger `-U<context_lines>` option for `git diff`,
# or give up if `context_lines` is already very large.
if context_lines == MAX_CONTEXT_LINES:
if context_lines == max_context_lines:
raise
logger.debug(
"AST verification failed. "
Expand Down
16 changes: 13 additions & 3 deletions src/darker/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,23 @@ def _validate_opcodes(opcodes: List[Tuple[str, int, int, int, int]]) -> None:


def opcodes_to_edit_linenums(
opcodes: List[Tuple[str, int, int, int, int]]
opcodes: List[Tuple[str, int, int, int, int]], context_lines: int
) -> Generator[int, None, None]:
"""Convert diff opcode to line number of edited lines in the destination file"""
"""Convert diff opcodes to line numbers of edited lines in the destination file
:param opcodes: The diff opcodes to convert
:param context_lines: The number of lines before and after an edited line to mark
edited as well
"""
_validate_opcodes(opcodes)
prev_chunk_end = 1
_tag, _i1, _i2, _j1, end = opcodes[-1]
for tag, _i1, _i2, j1, j2 in opcodes:
if tag != "equal":
yield from range(j1 + 1, j2 + 1)
chunk_end = min(j2 + 1 + context_lines, end + 1)
yield from range(max(j1 + 1 - context_lines, prev_chunk_end), chunk_end)
prev_chunk_end = chunk_end


def opcodes_to_chunks(
Expand Down
18 changes: 15 additions & 3 deletions src/darker/tests/test_diff.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from itertools import chain
from textwrap import dedent

import pytest
from black import FileMode, format_str

from darker.diff import (
Expand Down Expand Up @@ -141,7 +143,17 @@ def test_opcodes_to_chunks():
]


def test_opcodes_to_edit_linenums():
edit_linenums = list(opcodes_to_edit_linenums(OPCODES))
@pytest.mark.parametrize(
'context_lines, expect',
[
(0, [1, 4, 5, 13, 14, 17, 20, 22, 23, 27]),
(1, [[1, 6], [12, 24], [26, 28]]),
(2, [[1, 7], [11, 28]]),
],
)
def test_opcodes_to_edit_linenums(context_lines, expect):
edit_linenums = list(opcodes_to_edit_linenums(OPCODES, context_lines))
expect_ranges = [[n, n] if isinstance(n, int) else n for n in expect]
expect_linenums = list(chain(*(range(n[0], n[1] + 1) for n in expect_ranges)))

assert edit_linenums == [1, 4, 5, 13, 14, 17, 20, 22, 23, 27]
assert edit_linenums == expect_linenums