mirror of
https://github.com/Aider-AI/aider.git
synced 2025-05-31 09:44:59 +00:00
style: Run linter on patch_coder.py
This commit is contained in:
parent
f565f72679
commit
1ae5f23dc8
1 changed files with 134 additions and 115 deletions
|
@ -53,9 +53,7 @@ def _norm(line: str) -> str:
|
|||
return line.rstrip("\r")
|
||||
|
||||
|
||||
def find_context_core(
|
||||
lines: List[str], context: List[str], start: int
|
||||
) -> Tuple[int, int]:
|
||||
def find_context_core(lines: List[str], context: List[str], start: int) -> Tuple[int, int]:
|
||||
"""Finds context block, returns start index and fuzz level."""
|
||||
if not context:
|
||||
return start, 0
|
||||
|
@ -77,9 +75,7 @@ def find_context_core(
|
|||
return -1, 0
|
||||
|
||||
|
||||
def find_context(
|
||||
lines: List[str], context: List[str], start: int, eof: bool
|
||||
) -> Tuple[int, int]:
|
||||
def find_context(lines: List[str], context: List[str], start: int, eof: bool) -> Tuple[int, int]:
|
||||
"""Finds context, handling EOF marker."""
|
||||
if eof:
|
||||
# If EOF marker, first try matching at the very end
|
||||
|
@ -94,9 +90,7 @@ def find_context(
|
|||
return find_context_core(lines, context, start)
|
||||
|
||||
|
||||
def peek_next_section(
|
||||
lines: List[str], index: int
|
||||
) -> Tuple[List[str], List[Chunk], int, bool]:
|
||||
def peek_next_section(lines: List[str], index: int) -> Tuple[List[str], List[Chunk], int, bool]:
|
||||
"""
|
||||
Parses one section (context, -, + lines) of an Update block.
|
||||
Returns: (context_lines, chunks_in_section, next_index, is_eof)
|
||||
|
@ -150,7 +144,6 @@ def peek_next_section(
|
|||
# but strict format requires ' '. Raise error for strictness.
|
||||
raise DiffError(f"Invalid line prefix in update section: {line}")
|
||||
|
||||
|
||||
# If mode changes from add/delete back to keep, finalize the previous chunk
|
||||
if mode == "keep" and last_mode != "keep":
|
||||
if del_lines or ins_lines:
|
||||
|
@ -207,6 +200,7 @@ def identify_files_needed(text: str) -> List[str]:
|
|||
paths.add(norm_line[len("*** Delete File: ") :].strip())
|
||||
return list(paths)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# PatchCoder Class Implementation
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
@ -237,15 +231,20 @@ class PatchCoder(Coder):
|
|||
# or _norm(lines[-1]) != "*** End Patch"
|
||||
):
|
||||
# Tolerate missing sentinels if content looks like a patch action
|
||||
is_patch_like = any(_norm(line).startswith(
|
||||
is_patch_like = any(
|
||||
_norm(line).startswith(
|
||||
("@@", "*** Update File:", "*** Add File:", "*** Delete File:")
|
||||
) for line in lines)
|
||||
)
|
||||
for line in lines
|
||||
)
|
||||
if not is_patch_like:
|
||||
# If it doesn't even look like a patch, return empty
|
||||
self.io.tool_warning("Response does not appear to be in patch format.")
|
||||
return []
|
||||
# If it looks like a patch but lacks sentinels, try parsing anyway but warn.
|
||||
self.io.tool_warning("Patch format warning: Missing '*** Begin Patch'/'*** End Patch' sentinels.")
|
||||
self.io.tool_warning(
|
||||
"Patch format warning: Missing '*** Begin Patch'/'*** End Patch' sentinels."
|
||||
)
|
||||
start_index = 0
|
||||
else:
|
||||
start_index = 1 # Skip "*** Begin Patch"
|
||||
|
@ -259,14 +258,15 @@ class PatchCoder(Coder):
|
|||
# Use io.read_text to handle potential errors/encodings
|
||||
file_content = self.io.read_text(abs_path)
|
||||
if file_content is None:
|
||||
raise DiffError(f"File referenced in patch not found or could not be read: {rel_path}")
|
||||
raise DiffError(
|
||||
f"File referenced in patch not found or could not be read: {rel_path}"
|
||||
)
|
||||
current_files[rel_path] = file_content
|
||||
except FileNotFoundError:
|
||||
raise DiffError(f"File referenced in patch not found: {rel_path}")
|
||||
except IOError as e:
|
||||
raise DiffError(f"Error reading file {rel_path}: {e}")
|
||||
|
||||
|
||||
try:
|
||||
# Parse the patch text using adapted logic
|
||||
patch_obj = self._parse_patch_text(lines, start_index, current_files)
|
||||
|
@ -279,7 +279,6 @@ class PatchCoder(Coder):
|
|||
# Catch unexpected errors during parsing
|
||||
raise ValueError(f"Unexpected error parsing patch: {e}")
|
||||
|
||||
|
||||
def _parse_patch_text(
|
||||
self, lines: List[str], start_index: int, current_files: Dict[str, str]
|
||||
) -> Patch:
|
||||
|
@ -303,15 +302,19 @@ class PatchCoder(Coder):
|
|||
if norm_line.startswith("*** Update File: "):
|
||||
path = norm_line[len("*** Update File: ") :].strip()
|
||||
index += 1
|
||||
if not path: raise DiffError("Update File action missing path.")
|
||||
if path in patch.actions: raise DiffError(f"Duplicate action for file: {path}")
|
||||
if path not in current_files: raise DiffError(f"Update File Error - missing file content for: {path}")
|
||||
if not path:
|
||||
raise DiffError("Update File action missing path.")
|
||||
if path in patch.actions:
|
||||
raise DiffError(f"Duplicate action for file: {path}")
|
||||
if path not in current_files:
|
||||
raise DiffError(f"Update File Error - missing file content for: {path}")
|
||||
|
||||
move_to = None
|
||||
if index < len(lines) and _norm(lines[index]).startswith("*** Move to: "):
|
||||
move_to = _norm(lines[index])[len("*** Move to: ") :].strip()
|
||||
index += 1
|
||||
if not move_to: raise DiffError("Move to action missing path.")
|
||||
if not move_to:
|
||||
raise DiffError("Move to action missing path.")
|
||||
|
||||
file_content = current_files[path]
|
||||
action, index, fuzz = self._parse_update_file_sections(lines, index, file_content)
|
||||
|
@ -325,9 +328,14 @@ class PatchCoder(Coder):
|
|||
elif norm_line.startswith("*** Delete File: "):
|
||||
path = norm_line[len("*** Delete File: ") :].strip()
|
||||
index += 1
|
||||
if not path: raise DiffError("Delete File action missing path.")
|
||||
if path in patch.actions: raise DiffError(f"Duplicate action for file: {path}")
|
||||
if path not in current_files: raise DiffError(f"Delete File Error - file not found: {path}") # Check against known files
|
||||
if not path:
|
||||
raise DiffError("Delete File action missing path.")
|
||||
if path in patch.actions:
|
||||
raise DiffError(f"Duplicate action for file: {path}")
|
||||
if path not in current_files:
|
||||
raise DiffError(
|
||||
f"Delete File Error - file not found: {path}"
|
||||
) # Check against known files
|
||||
|
||||
patch.actions[path] = PatchAction(type=ActionType.DELETE, path=path)
|
||||
continue
|
||||
|
@ -336,8 +344,10 @@ class PatchCoder(Coder):
|
|||
elif norm_line.startswith("*** Add File: "):
|
||||
path = norm_line[len("*** Add File: ") :].strip()
|
||||
index += 1
|
||||
if not path: raise DiffError("Add File action missing path.")
|
||||
if path in patch.actions: raise DiffError(f"Duplicate action for file: {path}")
|
||||
if not path:
|
||||
raise DiffError("Add File action missing path.")
|
||||
if path in patch.actions:
|
||||
raise DiffError(f"Duplicate action for file: {path}")
|
||||
# Check if file exists in the context provided (should not for Add)
|
||||
# Note: We don't have *all* files, just needed ones. A full check requires FS access.
|
||||
# if path in current_files: raise DiffError(f"Add File Error - file already exists: {path}")
|
||||
|
@ -363,7 +373,6 @@ class PatchCoder(Coder):
|
|||
patch.fuzz = fuzz_accumulator
|
||||
return patch
|
||||
|
||||
|
||||
def _parse_update_file_sections(
|
||||
self, lines: List[str], index: int, file_content: str
|
||||
) -> Tuple[PatchAction, int, int]:
|
||||
|
@ -404,7 +413,10 @@ class PatchCoder(Coder):
|
|||
# Check if all scope lines match sequentially from temp_index
|
||||
match = True
|
||||
for i, scope in enumerate(scope_lines):
|
||||
if temp_index + i >= len(orig_lines) or _norm(orig_lines[temp_index + i]).strip() != scope:
|
||||
if (
|
||||
temp_index + i >= len(orig_lines)
|
||||
or _norm(orig_lines[temp_index + i]).strip() != scope
|
||||
):
|
||||
match = False
|
||||
break
|
||||
if match:
|
||||
|
@ -419,7 +431,10 @@ class PatchCoder(Coder):
|
|||
while temp_index < len(orig_lines):
|
||||
match = True
|
||||
for i, scope in enumerate(scope_lines):
|
||||
if temp_index + i >= len(orig_lines) or _norm(orig_lines[temp_index + i]).strip() != scope.strip():
|
||||
if (
|
||||
temp_index + i >= len(orig_lines)
|
||||
or _norm(orig_lines[temp_index + i]).strip() != scope.strip()
|
||||
):
|
||||
match = False
|
||||
break
|
||||
if match:
|
||||
|
@ -433,7 +448,6 @@ class PatchCoder(Coder):
|
|||
scope_txt = "\n".join(scope_lines)
|
||||
raise DiffError(f"Could not find scope context:\n{scope_txt}")
|
||||
|
||||
|
||||
# Peek and parse the next context/change section
|
||||
context_block, chunks_in_section, next_index, is_eof = peek_next_section(lines, index)
|
||||
|
||||
|
@ -463,10 +477,7 @@ class PatchCoder(Coder):
|
|||
|
||||
return action, index, total_fuzz
|
||||
|
||||
|
||||
def _parse_add_file_content(
|
||||
self, lines: List[str], index: int
|
||||
) -> Tuple[PatchAction, int]:
|
||||
def _parse_add_file_content(self, lines: List[str], index: int) -> Tuple[PatchAction, int]:
|
||||
"""Parses the content (+) lines for an Add File action."""
|
||||
added_lines: List[str] = []
|
||||
while index < len(lines):
|
||||
|
@ -499,7 +510,6 @@ class PatchCoder(Coder):
|
|||
action = PatchAction(type=ActionType.ADD, path="", new_content="\n".join(added_lines))
|
||||
return action, index
|
||||
|
||||
|
||||
def apply_edits(self, edits: List[PatchAction]):
|
||||
"""
|
||||
Applies the parsed PatchActions to the corresponding files.
|
||||
|
@ -527,14 +537,16 @@ class PatchCoder(Coder):
|
|||
path_obj.parent.mkdir(parents=True, exist_ok=True)
|
||||
# Ensure single trailing newline, matching reference behavior
|
||||
content_to_write = action.new_content
|
||||
if not content_to_write.endswith('\n'):
|
||||
content_to_write += '\n'
|
||||
if not content_to_write.endswith("\n"):
|
||||
content_to_write += "\n"
|
||||
self.io.write_text(full_path, content_to_write)
|
||||
|
||||
elif action.type == ActionType.DELETE:
|
||||
self.io.tool_output(f"Deleting {action.path}")
|
||||
if not path_obj.exists():
|
||||
self.io.tool_warning(f"DELETE Warning: File not found, skipping: {action.path}")
|
||||
self.io.tool_warning(
|
||||
f"DELETE Warning: File not found, skipping: {action.path}"
|
||||
)
|
||||
else:
|
||||
path_obj.unlink()
|
||||
|
||||
|
@ -550,18 +562,24 @@ class PatchCoder(Coder):
|
|||
# Apply the update logic using the parsed chunks
|
||||
new_content = self._apply_update(current_content, action, action.path)
|
||||
|
||||
target_full_path = self.abs_root_path(action.move_path) if action.move_path else full_path
|
||||
target_full_path = (
|
||||
self.abs_root_path(action.move_path) if action.move_path else full_path
|
||||
)
|
||||
target_path_obj = pathlib.Path(target_full_path)
|
||||
|
||||
if action.move_path:
|
||||
self.io.tool_output(f"Updating and moving {action.path} to {action.move_path}")
|
||||
self.io.tool_output(
|
||||
f"Updating and moving {action.path} to {action.move_path}"
|
||||
)
|
||||
# Check if target exists before overwriting/moving
|
||||
if target_path_obj.exists() and full_path != target_full_path:
|
||||
self.io.tool_warning(f"UPDATE Warning: Target file for move already exists, overwriting: {action.move_path}")
|
||||
self.io.tool_warning(
|
||||
"UPDATE Warning: Target file for move already exists, overwriting:"
|
||||
f" {action.move_path}"
|
||||
)
|
||||
else:
|
||||
self.io.tool_output(f"Updating {action.path}")
|
||||
|
||||
|
||||
# Ensure parent directory exists for target
|
||||
target_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
||||
self.io.write_text(target_full_path, new_content)
|
||||
|
@ -579,8 +597,9 @@ class PatchCoder(Coder):
|
|||
raise ValueError(f"Error applying action '{action.type}' to {action.path}: {e}")
|
||||
except Exception as e:
|
||||
# Catch unexpected errors during application
|
||||
raise ValueError(f"Unexpected error applying action '{action.type}' to {action.path}: {e}")
|
||||
|
||||
raise ValueError(
|
||||
f"Unexpected error applying action '{action.type}' to {action.path}: {e}"
|
||||
)
|
||||
|
||||
def _apply_update(self, text: str, action: PatchAction, path: str) -> str:
|
||||
"""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue