mirror of
https://github.com/aljazceru/Auto-GPT.git
synced 2026-01-05 15:24:23 +01:00
Add replace_in_file command (#4565)
Resubmission of #3643 --------- Co-authored-by: Reinier van der Leer <github@pwuts.nl>
This commit is contained in:
committed by
GitHub
parent
59d31b021d
commit
74e8a886e6
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import hashlib
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Generator, Literal
|
||||
|
||||
import requests
|
||||
@@ -224,6 +225,68 @@ def write_to_file(filename: str, text: str, config: Config) -> str:
|
||||
return f"Error: {err}"
|
||||
|
||||
|
||||
@command(
|
||||
"replace_in_file",
|
||||
"Replace text or code in a file",
|
||||
'"filename": "<filename>", '
|
||||
'"old_text": "<old_text>", "new_text": "<new_text>", '
|
||||
'"occurrence_index": "<occurrence_index>"',
|
||||
)
|
||||
def replace_in_file(
|
||||
filename: str, old_text: str, new_text: str, config: Config, occurrence_index=None
|
||||
):
|
||||
"""Update a file by replacing one or all occurrences of old_text with new_text using Python's built-in string
|
||||
manipulation and regular expression modules for cross-platform file editing similar to sed and awk.
|
||||
|
||||
Args:
|
||||
filename (str): The name of the file
|
||||
old_text (str): String to be replaced. \n will be stripped from the end.
|
||||
new_text (str): New string. \n will be stripped from the end.
|
||||
occurrence_index (int): Optional index of the occurrence to replace. If None, all occurrences will be replaced.
|
||||
|
||||
Returns:
|
||||
str: A message indicating whether the file was updated successfully or if there were no matches found for old_text
|
||||
in the file.
|
||||
|
||||
Raises:
|
||||
Exception: If there was an error updating the file.
|
||||
"""
|
||||
try:
|
||||
with open(filename, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
old_text = old_text.rstrip("\n")
|
||||
new_text = new_text.rstrip("\n")
|
||||
|
||||
if occurrence_index is None:
|
||||
new_content = content.replace(old_text, new_text)
|
||||
else:
|
||||
matches = list(re.finditer(re.escape(old_text), content))
|
||||
if not matches:
|
||||
return f"No matches found for {old_text} in {filename}"
|
||||
|
||||
if int(occurrence_index) >= len(matches):
|
||||
return f"Occurrence index {occurrence_index} is out of range for {old_text} in {filename}"
|
||||
|
||||
match = matches[int(occurrence_index)]
|
||||
start, end = match.start(), match.end()
|
||||
new_content = content[:start] + new_text + content[end:]
|
||||
|
||||
if content == new_content:
|
||||
return f"No matches found for {old_text} in {filename}"
|
||||
|
||||
with open(filename, "w", encoding="utf-8") as f:
|
||||
f.write(new_content)
|
||||
|
||||
with open(filename, "r", encoding="utf-8") as f:
|
||||
checksum = text_checksum(f.read())
|
||||
log_operation("update", filename, config, checksum=checksum)
|
||||
|
||||
return f"File {filename} updated successfully."
|
||||
except Exception as e:
|
||||
return "Error: " + str(e)
|
||||
|
||||
|
||||
@command(
|
||||
"append_to_file", "Append to file", '"filename": "<filename>", "text": "<text>"'
|
||||
)
|
||||
|
||||
@@ -268,6 +268,53 @@ def test_write_file_succeeds_if_content_different(
|
||||
assert result == "File written to successfully."
|
||||
|
||||
|
||||
# Update file testing
|
||||
def test_replace_in_file_all_occurrences(test_file, test_file_path, config):
|
||||
old_content = "This is a test file.\n we test file here\na test is needed"
|
||||
expected_content = (
|
||||
"This is a update file.\n we update file here\na update is needed"
|
||||
)
|
||||
test_file.write(old_content)
|
||||
test_file.close()
|
||||
file_ops.replace_in_file(test_file_path, "test", "update", config)
|
||||
with open(test_file_path) as f:
|
||||
new_content = f.read()
|
||||
print(new_content)
|
||||
print(expected_content)
|
||||
assert new_content == expected_content
|
||||
|
||||
|
||||
def test_replace_in_file_one_occurrence(test_file, test_file_path, config):
|
||||
old_content = "This is a test file.\n we test file here\na test is needed"
|
||||
expected_content = "This is a test file.\n we update file here\na test is needed"
|
||||
test_file.write(old_content)
|
||||
test_file.close()
|
||||
file_ops.replace_in_file(
|
||||
test_file_path, "test", "update", config, occurrence_index=1
|
||||
)
|
||||
with open(test_file_path) as f:
|
||||
new_content = f.read()
|
||||
|
||||
assert new_content == expected_content
|
||||
|
||||
|
||||
def test_replace_in_file_multiline_old_text(test_file, test_file_path, config):
|
||||
old_content = "This is a multi_line\ntest for testing\nhow well this function\nworks when the input\nis multi-lined"
|
||||
expected_content = "This is a multi_line\nfile. succeeded test\nis multi-lined"
|
||||
test_file.write(old_content)
|
||||
test_file.close()
|
||||
file_ops.replace_in_file(
|
||||
test_file_path,
|
||||
"\ntest for testing\nhow well this function\nworks when the input\n",
|
||||
"\nfile. succeeded test\n",
|
||||
config,
|
||||
)
|
||||
with open(test_file_path) as f:
|
||||
new_content = f.read()
|
||||
|
||||
assert new_content == expected_content
|
||||
|
||||
|
||||
def test_append_to_file(test_nested_file: Path, config):
|
||||
append_text = "This is appended text.\n"
|
||||
file_ops.write_to_file(test_nested_file, append_text, config)
|
||||
|
||||
Reference in New Issue
Block a user