Commit graph

2307 commits

Author SHA1 Message Date
Paul Gauthier
7c0ac4d92f Tell git to stop quoting the paths in ls-files 2023-07-11 08:12:44 -07:00
Paul Gauthier
c4e4d071fa Handle the case where we fail to expand a dir 2023-07-11 08:12:18 -07:00
Paul Gauthier
4024713f31 Updated HISTORY 2023-07-11 07:36:04 -07:00
Paul Gauthier
d636d02d96 Merge remote-tracking branch 'origin/main' 2023-07-11 07:33:12 -07:00
Paul Gauthier
d7ba886e66 added test_update_files_live_diff 2023-07-11 07:32:31 -07:00
Paul Gauthier
aacbcd32d4 bugfix live diffs in wholefile coder 2023-07-11 07:27:49 -07:00
paul-gauthier
57ef02f92e
Update faq.md 2023-07-10 19:35:19 -07:00
paul-gauthier
338c0a56d6
Update faq.md 2023-07-10 19:31:47 -07:00
Paul Gauthier
c20b1bb073 Merge remote-tracking branch 'origin/main' 2023-07-10 15:34:04 -07:00
Paul Gauthier
aedfa64eb9 Fix test 2023-07-10 15:33:46 -07:00
paul-gauthier
17e616d282
Merge pull request #80 from paul-gauthier/issue-57
The /add command should recurse into named subdirs per issue #57
2023-07-10 15:33:02 -07:00
Paul Gauthier
9bc450977d Remove last naive open()s 2023-07-10 15:32:23 -07:00
Paul Gauthier
baa11b0c0d cleanup 2023-07-10 15:23:25 -07:00
Paul Gauthier
93866ebe17 test name 2023-07-10 15:19:30 -07:00
Paul Gauthier
e4389ab7f7 add test in drop 2023-07-10 15:18:11 -07:00
Paul Gauthier
56f465b7f3 move the expansion into glob_filtered_to_repo so it works in drop too 2023-07-10 15:17:41 -07:00
Paul Gauthier
a88b2a70e8 cleanup 2023-07-10 15:10:23 -07:00
Paul Gauthier
79030d968f use pathlib to ensure the parent dir is retained 2023-07-10 13:27:43 -07:00
Paul Gauthier
65c12a73f6 aider: Refactored expand_subdir to use pathlib for recursively finding all files in the given directory.
# Aider chat conversation:

USER: make `expand_subdir` use pathlib

ASSISTANT: To modify the `expand_subdir` function to use `pathlib`, we need to modify the `aider/commands.py` file. Here are the changes:

```python
aider/commands.py
<<<<<<< ORIGINAL
def expand_subdir(file_path):
    for root, dirs, files in os.walk(file_path):
        for fname in files:
            yield fname
=======
from pathlib import Path

def expand_subdir(file_path):
    for file in Path(file_path).rglob('*'):
        if file.is_file():
            yield str(file)
>>>>>>> UPDATED
```

This change replaces the `os.walk` function with the `Path.rglob` method from `pathlib`, which recursively finds all files in the given directory. The `is_file` method is used to ensure we only yield files, not directories. The `str` function is used to convert the `Path` object to a string.
2023-07-10 13:27:11 -07:00
Paul Gauthier
f48aeac88b wip 2023-07-10 13:26:37 -07:00
Paul Gauthier
4b91adabdc aider: The test case has been modified to add files to the directory and ensure they are added correctly.
# Aider chat conversation:

USER: put some files in the test_dir, and the test shouldn't look for the exception. it should make sure the files were added

ASSISTANT: To modify the test case to add files to the directory and ensure they are added correctly, we need to modify the `tests/test_commands.py` file.

Here is the proposed change:

```python
tests/test_commands.py
<<<<<<< ORIGINAL
    def test_cmd_add_directory(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 directory
        os.mkdir("test_dir")

        # Call the cmd_add method with a directory
        with self.assertRaises(IsADirectoryError):
            commands.cmd_add("test_dir")
=======
    def test_cmd_add_directory(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 directory and add files to it
        os.mkdir("test_dir")
        with open("test_dir/test_file1.txt", "w") as f:
            f.write("Test file 1")
        with open("test_dir/test_file2.txt", "w") as f:
            f.write("Test file 2")

        # Call the cmd_add method with a directory
        commands.cmd_add("test_dir")

        # Check if the files have been added to the chat session
        self.assertIn(str(Path("test_dir/test_file1.txt").resolve()), coder.abs_fnames)
        self.assertIn(str(Path("test_dir/test_file2.txt").resolve()), coder.abs_fnames)
>>>>>>> UPDATED
```

This new test case `test_cmd_add_directory` creates a directory named `test_dir`, adds two files to it, and attempts to add the directory using the `cmd_add` method. We then check if the files in the directory have been added to the chat session.
2023-07-10 13:19:11 -07:00
Paul Gauthier
8be2f8086c aider: Add a test case to reproduce the issue of trying to add a directory using the /add command.
# Aider chat conversation:

USER: add a test case to reproduce this issue: Trying to add just a directory makes the program throw the following and exit:

> /add src/components

Traceback (most recent call last):
  File "/home/palmerd/.local/bin/aider", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/home/palmerd/.local/lib/python3.11/site-packages/aider/main.py", line 369, in main
    coder.run()
  File "/home/palmerd/.local/lib/python3.11/site-packages/aider/coders/base_coder.py", line 382, in run
    new_user_message = self.run_loop()
                       ^^^^^^^^^^^^^^^
  File "/home/palmerd/.local/lib/python3.11/site-packages/aider/coders/base_coder.py", line 446, in run_loop
    return self.commands.run(inp)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/palmerd/.local/lib/python3.11/site-packages/aider/commands.py", line 60, in run
    return self.do_run(matching_commands[0][1:], rest_inp)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/palmerd/.local/lib/python3.11/site-packages/aider/commands.py", line 45, in do_run
    return cmd_method(args)
           ^^^^^^^^^^^^^^^^
  File "/home/palmerd/.local/lib/python3.11/site-packages/aider/commands.py", line 264, in cmd_add
    content = self.io.read_text(abs_file_path)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/palmerd/.local/lib/python3.11/site-packages/aider/io.py", line 142, in read_text
    with open(str(filename), "r", encoding=self.encoding) as f:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
IsADirectoryError: [Errno 21] Is a directory: '/home/palmerd/vue-frontend/src/components'

ASSISTANT: To reproduce this issue, we need to create a test case that tries to add a directory using the `/add` command. However, the code you've provided is not designed to handle test cases.

Could you please provide the test suite or the file where the test cases are written so that I can add a new test case?

USER: I added these *read-write* files: tests/test_commands.py

ASSISTANT: Great, we can add a test case in the `tests/test_commands.py` file. This test case will attempt to add a directory and check if the appropriate error is handled.

Here is the proposed change:

```python
tests/test_commands.py
<<<<<<< ORIGINAL
    def test_cmd_add_no_match(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 a non-existent file pattern
        commands.cmd_add("*.nonexistent")

        # Check if no files have been added to the chat session
        self.assertEqual(len(coder.abs_fnames), 0)
=======
    def test_cmd_add_no_match(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 a non-existent file pattern
        commands.cmd_add("*.nonexistent")

        # Check if no files have been added to the chat session
        self.assertEqual(len(coder.abs_fnames), 0)

    def test_cmd_add_directory(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 directory
        os.mkdir("test_dir")

        # Call the cmd_add method with a directory
        with self.assertRaises(IsADirectoryError):
            commands.cmd_add("test_dir")
>>>>>>> UPDATED
```

This new test case `test_cmd_add_directory` creates a directory named `test_dir` and attempts to add it using the `cmd_add` method. We expect an `IsADirectoryError` to be raised in this scenario.
2023-07-10 13:17:55 -07:00
Paul Gauthier
3857a09a70 10 retries 2023-07-10 07:38:17 -07:00
Paul Gauthier
96b9e49a77 faq 2023-07-10 07:26:12 -07:00
Paul Gauthier
bffb557896 copy 2023-07-10 07:24:49 -07:00
Paul Gauthier
39912fdc09 more help 2023-07-10 07:23:17 -07:00
Paul Gauthier
a18b5dcb83 padding 2023-07-09 21:44:03 -07:00
Paul Gauthier
707549b67d colors 2023-07-09 21:41:02 -07:00
Paul Gauthier
b37730e3f9 copy 2023-07-09 19:13:26 -07:00
Paul Gauthier
0ede129bc9 dots 2023-07-09 19:11:56 -07:00
Paul Gauthier
e26515ecf5 make li blue too 2023-07-09 07:05:43 -07:00
Paul Gauthier
1b90142332 copy 2023-07-09 06:57:33 -07:00
Paul Gauthier
1837677b72 updated examples readme 2023-07-09 06:55:22 -07:00
Paul Gauthier
620125bda5 smaller dots 2023-07-09 06:54:33 -07:00
Paul Gauthier
6abf71367b added divs 2023-07-09 06:48:12 -07:00
Paul Gauthier
6b43fdac4a Removed old transcript styling 2023-07-09 06:20:19 -07:00
Paul Gauthier
156b56d601 Added .chat-terminal styling 2023-07-09 06:15:42 -07:00
Paul Gauthier
b83f184d42 markdown=1 2023-07-08 19:25:33 -07:00
Paul Gauthier
30c01aa62f removed raw 2023-07-08 19:23:14 -07:00
Paul Gauthier
e9346ed56a use raw 2023-07-08 19:19:34 -07:00
Paul Gauthier
28aa5535be added div to transcript 2023-07-08 19:05:53 -07:00
Paul Gauthier
2e437893d4 aider: Replace os.path.expanduser("~/.gitconfig") with str(Path.home() / ".gitconfig") in main function.
# Aider chat conversation:

USER: nice. use Path not os `expanduser`

ASSISTANT: To replace `os.path.expanduser` with `Path`, we need to modify the `main` function in the `aider/main.py` file. Here is the change:

```python
aider/main.py
<<<<<<< ORIGINAL
            global_git_config = git.GitConfigParser([os.path.expanduser("~/.gitconfig")], read_only=True)
=======
            global_git_config = git.GitConfigParser([str(Path.home() / ".gitconfig")], read_only=True)
>>>>>>> UPDATED
```

This change will make the code use `Path.home()` to get the home directory instead of `os.path.expanduser("~")`. The `Path` object is then converted to a string before being passed to `git.GitConfigParser`.
2023-07-08 18:42:00 -07:00
Paul Gauthier
3a6112377f aider: Change the code to check the global git configuration for the user name and email when creating a repo.
# Aider chat conversation:

USER: i have a global git name and email, but the git create code here isn't noticing and is setting the example name/email when it makes a repo

ASSISTANT: To fix this, we need to modify the `main` function in the `aider/main.py` file. Specifically, we need to change the way it checks for the global git name and email. Instead of checking the local git configuration, we should check the global git configuration.

Here is the change:

```python
aider/main.py
<<<<<<< ORIGINAL
            with repo.config_writer() as git_config:
                if not git_config.has_option("user", "name"):
                    git_config.set_value("user", "name", "Your Name")
                    io.tool_error('Update git name with: git config --global user.name "Your Name"')
                if not git_config.has_option("user", "email"):
                    git_config.set_value("user", "email", "you@example.com")
                    io.tool_error(
                        'Update git email with: git config --global user.email "you@example.com"'
                    )
=======
            global_git_config = git.GitConfigParser([os.path.expanduser("~/.gitconfig")], read_only=True)
            with repo.config_writer() as git_config:
                if not global_git_config.has_option("user", "name"):
                    git_config.set_value("user", "name", "Your Name")
                    io.tool_error('Update git name with: git config --global user.name "Your Name"')
                if not global_git_config.has_option("user", "email"):
                    git_config.set_value("user", "email", "you@example.com")
                    io.tool_error(
                        'Update git email with: git config --global user.email "you@example.com"'
                    )
>>>>>>> UPDATED
```

This change will make the code check the global git configuration (`~/.gitconfig`) for the user name and email. If they are not found, it will set the local git configuration with the example name and email and display a message to the user to update their global git configuration.
2023-07-08 18:41:18 -07:00
Paul Gauthier
f6b0d2b225 reorder args 2023-07-08 12:01:11 -07:00
Paul Gauthier
b65d0d2af3 reorder args 2023-07-08 11:55:59 -07:00
Paul Gauthier
e83e9c6ab0 Added --light-mode and made default colors acceptable for dark or light bgs 2023-07-08 11:02:31 -07:00
Paul Gauthier
8cb50a8a2e Added error color to dark mode 2023-07-08 10:50:01 -07:00
Paul Gauthier
3040409590 aider: The test is modified to include the missing param argument when raising InvalidRequestError.
# Aider chat conversation:

USER: I ran this command:

 pytest tests/test_coder.py -k test_run_with_invalid_request_error

And got this output:

============================= test session starts ==============================
platform darwin -- Python 3.11.3, pytest-7.3.1, pluggy-1.0.0
rootdir: /Users/gauthier/Projects/aider
configfile: pytest.ini
collected 14 items / 13 deselected / 1 selected

tests/test_coder.py F                                                    [100%]

=================================== FAILURES ===================================
________________ TestCoder.test_run_with_invalid_request_error _________________

self = <tests.test_coder.TestCoder testMethod=test_run_with_invalid_request_error>
mock_chat_completion_create = <MagicMock name='create' id='4934396624'>

    @patch("aider.coders.base_coder.openai.ChatCompletion.create")
    def test_run_with_invalid_request_error(self, mock_chat_completion_create):
        # Mock the IO object
        mock_io = MagicMock()

        # Initialize the Coder object with the mocked IO and mocked repo
        coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")

        # Set up the mock to raise InvalidRequestError
>       mock_chat_completion_create.side_effect = openai.error.InvalidRequestError("Invalid request")
E       TypeError: InvalidRequestError.__init__() missing 1 required positional argument: 'param'

tests/test_coder.py:355: TypeError
=========================== short test summary info ============================
FAILED tests/test_coder.py::TestCoder::test_run_with_invalid_request_error - ...
======================= 1 failed, 13 deselected in 1.04s =======================

ASSISTANT: The `openai.error.InvalidRequestError` requires two positional arguments: `message` and `param`. The `param` argument is used to specify the parameter that caused the invalid request.

Let's modify the test to include a `param` when raising the `InvalidRequestError`.

Here is the change:

```python
tests/test_coder.py
<<<<<<< ORIGINAL
    @patch("aider.coders.base_coder.openai.ChatCompletion.create")
    def test_run_with_invalid_request_error(self, mock_chat_completion_create):
        # Mock the IO object
        mock_io = MagicMock()

        # Initialize the Coder object with the mocked IO and mocked repo
        coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")

        # Set up the mock to raise InvalidRequestError
        mock_chat_completion_create.side_effect = openai.error.InvalidRequestError("Invalid request")

        # Call the run method and assert that InvalidRequestError is raised
        with self.assertRaises(openai.error.InvalidRequestError):
            coder.run(with_message="hi")
=======
    @patch("aider.coders.base_coder.openai.ChatCompletion.create")
    def test_run_with_invalid_request_error(self, mock_chat_completion_create):
        # Mock the IO object
        mock_io = MagicMock()

        # Initialize the Coder object with the mocked IO and mocked repo
        coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")

        # Set up the mock to raise InvalidRequestError
        mock_chat_completion_create.side_effect = openai.error.InvalidRequestError("Invalid request", "param")

        # Call the run method and assert that InvalidRequestError is raised
        with self.assertRaises(openai.error.InvalidRequestError):
            coder.run(with_message="hi")
>>>>>>> UPDATED
```

This change should fix the `TypeError` you're seeing in your test run.
2023-07-08 09:27:43 -07:00
Paul Gauthier
d3dac2fac6 aider: Add a test that mocks openai.ChatCompletion.create to throw an openai.error.InvalidRequestError and make sure it bubbles all the way up and out of the Coder class.
# Aider chat conversation:

USER: add a test that mocks openai.ChatCompletion.create to throw an openai.error.InvalidRequestError and make sure it bubbles all the way up and out of the Coder class. use coder.run as the entrypoint for the test

ASSISTANT: To add this test, we need to modify the `tests/test_coder.py` file. We will add a new test method `test_run_with_invalid_request_error` that mocks `openai.ChatCompletion.create` to throw an `openai.error.InvalidRequestError`. We will then call `coder.run` and assert that the `InvalidRequestError` is raised.

Here is the change:

```python
tests/test_coder.py
<<<<<<< ORIGINAL
    if __name__ == "__main__":
        unittest.main()
=======
    @patch("aider.coders.base_coder.openai.ChatCompletion.create")
    def test_run_with_invalid_request_error(self, mock_chat_completion_create):
        # Mock the IO object
        mock_io = MagicMock()

        # Initialize the Coder object with the mocked IO and mocked repo
        coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")

        # Set up the mock to raise InvalidRequestError
        mock_chat_completion_create.side_effect = openai.error.InvalidRequestError("Invalid request")

        # Call the run method and assert that InvalidRequestError is raised
        with self.assertRaises(openai.error.InvalidRequestError):
            coder.run(with_message="hi")

    if __name__ == "__main__":
        unittest.main()
>>>>>>> UPDATED
```

This test will ensure that if `openai.ChatCompletion.create` throws an `InvalidRequestError`, it will propagate up and out of the `Coder` class.
2023-07-08 09:26:27 -07:00
Paul Gauthier
bcc8723fa7 copy 2023-07-08 09:23:05 -07:00