Merge branch 'main' into glob-add

This commit is contained in:
Paul Gauthier 2023-07-06 17:53:46 -07:00
commit cb2b2c5ce3
22 changed files with 465 additions and 94 deletions

View file

@ -1,5 +1,7 @@
import os
import tempfile
import unittest
from pathlib import Path
from unittest.mock import MagicMock, patch
import openai
@ -7,6 +9,8 @@ import requests
from aider import models
from aider.coders import Coder
from aider.dump import dump # noqa: F401
from aider.io import InputOutput
class TestCoder(unittest.TestCase):
@ -177,6 +181,132 @@ class TestCoder(unittest.TestCase):
# Assert that print was called once
mock_print.assert_called_once()
def test_run_with_file_deletion(self):
# Create a few temporary files
if __name__ == "__main__":
unittest.main()
tempdir = Path(tempfile.mkdtemp())
file1 = tempdir / "file1.txt"
file2 = tempdir / "file2.txt"
file1.touch()
file2.touch()
files = [file1, file2]
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(
models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", fnames=files
)
def mock_send(*args, **kwargs):
coder.partial_response_content = "ok"
coder.partial_response_function_call = dict()
coder.send = MagicMock(side_effect=mock_send)
# Call the run method with a message
coder.run(with_message="hi")
self.assertEqual(len(coder.abs_fnames), 2)
file1.unlink()
# Call the run method again with a message
coder.run(with_message="hi")
self.assertEqual(len(coder.abs_fnames), 1)
def test_run_with_file_unicode_error(self):
# Create a few temporary files
_, file1 = tempfile.mkstemp()
_, file2 = tempfile.mkstemp()
files = [file1, file2]
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(
models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", fnames=files
)
def mock_send(*args, **kwargs):
coder.partial_response_content = "ok"
coder.partial_response_function_call = dict()
coder.send = MagicMock(side_effect=mock_send)
# Call the run method with a message
coder.run(with_message="hi")
self.assertEqual(len(coder.abs_fnames), 2)
# Write some non-UTF8 text into the file
with open(file1, "wb") as f:
f.write(b"\x80abc")
# Call the run method again with a message
coder.run(with_message="hi")
self.assertEqual(len(coder.abs_fnames), 1)
def test_choose_fence(self):
# Create a few temporary files
_, file1 = tempfile.mkstemp()
with open(file1, "wb") as f:
f.write(b"this contains ``` backticks")
files = [file1]
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(
models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", fnames=files
)
def mock_send(*args, **kwargs):
coder.partial_response_content = "ok"
coder.partial_response_function_call = dict()
coder.send = MagicMock(side_effect=mock_send)
# Call the run method with a message
coder.run(with_message="hi")
self.assertNotEqual(coder.fence[0], "```")
def test_run_with_file_utf_unicode_error(self):
"make sure that we honor InputOutput(encoding) and don't just assume utf-8"
# Create a few temporary files
_, file1 = tempfile.mkstemp()
_, file2 = tempfile.mkstemp()
files = [file1, file2]
encoding = "utf-16"
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(
models.GPT4,
None,
io=InputOutput(encoding=encoding),
openai_api_key="fake_key",
fnames=files,
)
def mock_send(*args, **kwargs):
coder.partial_response_content = "ok"
coder.partial_response_function_call = dict()
coder.send = MagicMock(side_effect=mock_send)
# Call the run method with a message
coder.run(with_message="hi")
self.assertEqual(len(coder.abs_fnames), 2)
some_content_which_will_error_if_read_with_encoding_utf8 = "ÅÍÎÏ".encode(encoding)
with open(file1, "wb") as f:
f.write(some_content_which_will_error_if_read_with_encoding_utf8)
coder.run(with_message="hi")
# both files should still be here
self.assertEqual(len(coder.abs_fnames), 2)
if __name__ == "__main__":
unittest.main()

View file

@ -1,10 +1,15 @@
import codecs
import os
import shutil
import sys
import tempfile
from io import StringIO
from unittest import TestCase
from aider import models
from aider.coders import Coder
from aider.commands import Commands
from aider.dump import dump # noqa: F401
from aider.io import InputOutput
@ -18,6 +23,21 @@ class TestCommands(TestCase):
os.chdir(self.original_cwd)
shutil.rmtree(self.tempdir)
def test_cmd_add(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Call the cmd_add method with 'foo.txt' and 'bar.txt' as a single string
commands.cmd_add("foo.txt bar.txt")
# Check if both files have been created in the temporary directory
self.assertTrue(os.path.exists("foo.txt"))
self.assertTrue(os.path.exists("bar.txt"))
def test_cmd_add_with_glob_patterns(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
@ -80,3 +100,43 @@ class TestCommands(TestCase):
# Check if the Python files have been removed from the chat session
self.assertIn(os.path.abspath("test1.py"), coder.abs_fnames)
self.assertNotIn(os.path.abspath("test2.py"), coder.abs_fnames)
def test_cmd_add_bad_encoding(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Create a new file foo.bad which will fail to decode as utf-8
with codecs.open("foo.bad", "w", encoding="iso-8859-15") as f:
f.write("ÆØÅ") # Characters not present in utf-8
commands.cmd_add("foo.bad")
self.assertEqual(coder.abs_fnames, set())
def test_cmd_tokens(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
commands.cmd_add("foo.txt bar.txt")
# Redirect the standard output to an instance of io.StringIO
stdout = StringIO()
sys.stdout = stdout
commands.cmd_tokens("")
# Reset the standard output
sys.stdout = sys.__stdout__
# Get the console output
console_output = stdout.getvalue()
self.assertIn("foo.txt", console_output)
self.assertIn("bar.txt", console_output)

View file

@ -1,11 +1,26 @@
# flake8: noqa: E501
import tempfile
import unittest
from pathlib import Path
from unittest.mock import MagicMock, patch
from aider import models
from aider.coders import Coder
from aider.coders import editblock_coder as eb
from aider.dump import dump # noqa: F401
from aider.io import InputOutput
class TestUtils(unittest.TestCase):
def setUp(self):
self.patcher = patch("aider.coders.base_coder.check_model_availability")
self.mock_check = self.patcher.start()
self.mock_check.return_value = True
def tearDown(self):
self.patcher.stop()
def test_replace_most_similar_chunk(self):
whole = "This is a sample text.\nAnother line of text.\nYet another line.\n"
part = "This is a sample text"
@ -223,6 +238,85 @@ These changes replace the `subprocess.run` patches with `subprocess.check_output
result = eb.replace_part_with_missing_leading_whitespace(whole, part, replace)
self.assertEqual(result, expected_output)
def test_full_edit(self):
# Create a few temporary files
_, file1 = tempfile.mkstemp()
with open(file1, "w", encoding="utf-8") as f:
f.write("one\ntwo\nthree\n")
files = [file1]
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(
models.GPT4, "diff", io=InputOutput(), openai_api_key="fake_key", fnames=files
)
def mock_send(*args, **kwargs):
coder.partial_response_content = f"""
Do this:
{Path(file1).name}
<<<<<<< ORIGINAL
two
=======
new
>>>>>>> UPDATED
"""
coder.partial_response_function_call = dict()
coder.send = MagicMock(side_effect=mock_send)
# Call the run method with a message
coder.run(with_message="hi")
content = Path(file1).read_text(encoding="utf-8")
self.assertEqual(content, "one\nnew\nthree\n")
def test_full_edit_dry_run(self):
# Create a few temporary files
_, file1 = tempfile.mkstemp()
orig_content = "one\ntwo\nthree\n"
with open(file1, "w", encoding="utf-8") as f:
f.write(orig_content)
files = [file1]
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(
models.GPT4,
"diff",
io=InputOutput(dry_run=True),
openai_api_key="fake_key",
fnames=files,
dry_run=True,
)
def mock_send(*args, **kwargs):
coder.partial_response_content = f"""
Do this:
{Path(file1).name}
<<<<<<< ORIGINAL
two
=======
new
>>>>>>> UPDATED
"""
coder.partial_response_function_call = dict()
coder.send = MagicMock(side_effect=mock_send)
# Call the run method with a message
coder.run(with_message="hi")
content = Path(file1).read_text(encoding="utf-8")
self.assertEqual(content, orig_content)
if __name__ == "__main__":
unittest.main()

View file

@ -3,6 +3,7 @@ import tempfile
import unittest
from unittest.mock import patch
from aider.io import InputOutput
from aider.repomap import RepoMap
@ -21,7 +22,8 @@ class TestRepoMap(unittest.TestCase):
with open(os.path.join(temp_dir, file), "w") as f:
f.write("")
repo_map = RepoMap(root=temp_dir)
io = InputOutput()
repo_map = RepoMap(root=temp_dir, io=io)
other_files = [os.path.join(temp_dir, file) for file in test_files]
result = repo_map.get_repo_map([], other_files)
@ -65,7 +67,8 @@ print(my_function(3, 4))
with open(os.path.join(temp_dir, test_file3), "w") as f:
f.write(file_content3)
repo_map = RepoMap(root=temp_dir)
io = InputOutput()
repo_map = RepoMap(root=temp_dir, io=io)
other_files = [
os.path.join(temp_dir, test_file1),
os.path.join(temp_dir, test_file2),
@ -83,7 +86,7 @@ print(my_function(3, 4))
def test_check_for_ctags_failure(self):
with patch("subprocess.run") as mock_run:
mock_run.side_effect = Exception("ctags not found")
repo_map = RepoMap()
repo_map = RepoMap(io=InputOutput())
self.assertFalse(repo_map.has_ctags)
def test_check_for_ctags_success(self):
@ -100,7 +103,7 @@ print(my_function(3, 4))
b' status = main()$/", "kind": "variable"}'
),
]
repo_map = RepoMap()
repo_map = RepoMap(io=InputOutput())
self.assertTrue(repo_map.has_ctags)
def test_get_repo_map_without_ctags(self):
@ -120,7 +123,7 @@ print(my_function(3, 4))
with open(os.path.join(temp_dir, file), "w") as f:
f.write("")
repo_map = RepoMap(root=temp_dir)
repo_map = RepoMap(root=temp_dir, io=InputOutput())
repo_map.has_ctags = False # force it off
other_files = [os.path.join(temp_dir, file) for file in test_files]

View file

@ -3,8 +3,10 @@ import shutil
import tempfile
import unittest
from pathlib import Path
from unittest.mock import MagicMock, patch
from aider import models
from aider.coders import Coder
from aider.coders.wholefile_coder import WholeFileCoder
from aider.io import InputOutput
@ -15,10 +17,16 @@ class TestWholeFileCoder(unittest.TestCase):
self.tempdir = tempfile.mkdtemp()
os.chdir(self.tempdir)
self.patcher = patch("aider.coders.base_coder.check_model_availability")
self.mock_check = self.patcher.start()
self.mock_check.return_value = True
def tearDown(self):
os.chdir(self.original_cwd)
shutil.rmtree(self.tempdir, ignore_errors=True)
self.patcher.stop()
def test_update_files(self):
# Create a sample file in the temporary directory
sample_file = "sample.txt"
@ -198,6 +206,45 @@ after b
self.assertEqual(fname_a.read_text(), "after a\n")
self.assertEqual(fname_b.read_text(), "after b\n")
def test_full_edit(self):
# Create a few temporary files
_, file1 = tempfile.mkstemp()
with open(file1, "w", encoding="utf-8") as f:
f.write("one\ntwo\nthree\n")
files = [file1]
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(
models.GPT4, "whole", io=InputOutput(), openai_api_key="fake_key", fnames=files
)
# no trailing newline so the response content below doesn't add ANOTHER newline
new_content = "new\ntwo\nthree"
def mock_send(*args, **kwargs):
coder.partial_response_content = f"""
Do this:
{Path(file1).name}
```
{new_content}
```
"""
coder.partial_response_function_call = dict()
coder.send = MagicMock(side_effect=mock_send)
# Call the run method with a message
coder.run(with_message="hi")
content = Path(file1).read_text(encoding="utf-8")
# check for one trailing newline
self.assertEqual(content, new_content + "\n")
if __name__ == "__main__":
unittest.main()