fix: Normalize whitespace when comparing patch context lines (#6541)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Graham Neubig
2025-02-10 13:53:39 -05:00
committed by GitHub
parent 2b40a92943
commit 7860055f8c
2 changed files with 90 additions and 6 deletions

View File

@@ -94,12 +94,17 @@ def apply_diff(diff, text, reverse=False, use_patch=False):
hunk=hunk,
)
if lines[old - 1] != line:
raise HunkApplyException(
'context line {n}, "{line}" does not match "{sl}"'.format(
n=old, line=line, sl=lines[old - 1]
),
hunk=hunk,
)
# Try to normalize whitespace by replacing multiple spaces with a single space
# This helps with patches that have different indentation levels
normalized_line = ' '.join(line.split())
normalized_source = ' '.join(lines[old - 1].split())
if normalized_line != normalized_source:
raise HunkApplyException(
'context line {n}, "{line}" does not match "{sl}"'.format(
n=old, line=line, sl=lines[old - 1]
),
hunk=hunk,
)
# for calculating the old line
r = 0

View File

@@ -0,0 +1,79 @@
from openhands.resolver.patching.apply import apply_diff
from openhands.resolver.patching.patch import parse_patch
def test_patch_whitespace_mismatch():
"""Test that the patch application succeeds even when whitespace doesn't match."""
# Original content has a line with spaces
original_content = """class Example:
def method(self):
pass
def another(self):
pass"""
# Patch expects an empty line (no spaces)
patch_text = """diff --git a/example.py b/example.py
index 1234567..89abcdef 100644
--- a/example.py
+++ b/example.py
@@ -2,6 +2,10 @@ class Example:
def method(self):
pass
+ new_field: str = "value"
+
def another(self):
pass"""
patch = next(parse_patch(patch_text))
# The patch should still work because we normalize whitespace
new_content = apply_diff(patch, original_content)
assert new_content == [
'class Example:',
' def method(self):',
' pass',
'',
' new_field: str = "value"',
'',
' def another(self):',
' pass',
]
def test_patch_whitespace_match():
"""Test that the patch application succeeds when whitespace matches."""
# Original content has an empty line (no spaces)
original_content = """class Example:
def method(self):
pass
def another(self):
pass"""
# Patch expects an empty line (no spaces)
patch_text = """diff --git a/example.py b/example.py
index 1234567..89abcdef 100644
--- a/example.py
+++ b/example.py
@@ -2,6 +2,10 @@ class Example:
def method(self):
pass
+ new_field: str = "value"
+
def another(self):
pass"""
patch = next(parse_patch(patch_text))
new_content = apply_diff(patch, original_content)
assert new_content == [
'class Example:',
' def method(self):',
' pass',
'',
' new_field: str = "value"',
'',
' def another(self):',
' pass',
]