aider: Fixed IndexError in find_original_update_blocks function.

# Context:
USER: I ran this command:

 pytest tests/test_utils.py

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
collected 11 items

tests/test_utils.py F..........                                          [100%]

=================================== FAILURES ===================================
__________________ TestUtils.test_false_incomplete_edit_block __________________

content = '\nNo problem! Here are the changes to patch `subprocess.check_output` instead of `subprocess.run` in both tests:\n\n`...h `subprocess.check_output` patches in both `test_check_for_ctags_failure` and `test_check_for_ctags_success` tests.\n'

    def find_original_update_blocks(content):
        # make sure we end with a newline, otherwise the regex will miss <<UPD on the last line
        if not content.endswith("\n"):
            content = content + "\n"

        pieces = re.split(split_re, content)

        pieces.reverse()
        processed = []

        try:
            while pieces:
                cur = pieces.pop()

                if cur in (DIVIDER, UPDATED):
                    processed.append(cur)
                    raise ValueError(f"Unexpected {cur}")

                if cur.strip() != ORIGINAL:
                    processed.append(cur)
                    continue

                processed.append(cur)  # original_marker

                filename = processed[-2].splitlines()[-1].strip()
                if not len(filename) or "`" in filename:
>                   filename = processed[-2].splitlines()[-2].strip()
E                   IndexError: list index out of range

aider/utils.py:234: IndexError

During handling of the above exception, another exception occurred:

self = <tests.test_utils.TestUtils testMethod=test_false_incomplete_edit_block>

        def test_false_incomplete_edit_block(self):
            edit = """
    No problem! Here are the changes to patch `subprocess.check_output` instead of `subprocess.run` in both tests:

    ```python
    tests/test_repomap.py
    <<<<<<< ORIGINAL
        def test_check_for_ctags_failure(self):
            with patch("subprocess.run") as mock_run:
                mock_run.side_effect = Exception("ctags not found")
    =======
        def test_check_for_ctags_failure(self):
            with patch("subprocess.check_output") as mock_check_output:
                mock_check_output.side_effect = Exception("ctags not found")
    >>>>>>> UPDATED

    <<<<<<< ORIGINAL
        def test_check_for_ctags_success(self):
            with patch("subprocess.run") as mock_run:
                mock_run.return_value = CompletedProcess(args=["ctags", "--version"], returncode=0, stdout='''{
      "_type": "tag",
      "name": "status",
      "path": "aider/main.py",
      "pattern": "/^    status = main()$/",
      "kind": "variable"
    }''')
    =======
        def test_check_for_ctags_success(self):
            with patch("subprocess.check_output") as mock_check_output:
                mock_check_output.return_value = '''{
      "_type": "tag",
      "name": "status",
      "path": "aider/main.py",
      "pattern": "/^    status = main()$/",
      "kind": "variable"
    }'''
    >>>>>>> UPDATED
    ```

    These changes replace the `subprocess.run` patches with `subprocess.check_output` patches in both `test_check_for_ctags_failure` and `test_check_for_ctags_success` tests.
    """
            # Should not raise a ValueError
>           list(utils.find_original_update_blocks(edit))

tests/test_utils.py:199:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

content = '\nNo problem! Here are the changes to patch `subprocess.check_output` instead of `subprocess.run` in both tests:\n\n`...h `subprocess.check_output` patches in both `test_check_for_ctags_failure` and `test_check_for_ctags_success` tests.\n'

    def find_original_update_blocks(content):
        # make sure we end with a newline, otherwise the regex will miss <<UPD on the last line
        if not content.endswith("\n"):
            content = content + "\n"

        pieces = re.split(split_re, content)

        pieces.reverse()
        processed = []

        try:
            while pieces:
                cur = pieces.pop()

                if cur in (DIVIDER, UPDATED):
                    processed.append(cur)
                    raise ValueError(f"Unexpected {cur}")

                if cur.strip() != ORIGINAL:
                    processed.append(cur)
                    continue

                processed.append(cur)  # original_marker

                filename = processed[-2].splitlines()[-1].strip()
                if not len(filename) or "`" in filename:
                    filename = processed[-2].splitlines()[-2].strip()
                    if not len(filename) or "`" in filename:
                        raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")

                original_text = pieces.pop()
                processed.append(original_text)

                divider_marker = pieces.pop()
                processed.append(divider_marker)
                if divider_marker.strip() != DIVIDER:
                    raise ValueError(f"Expected {DIVIDER}")

                updated_text = pieces.pop()

                updated_marker = pieces.pop()
                if updated_marker.strip() != UPDATED:
                    raise ValueError(f"Expected {UPDATED}")

                yield filename, original_text, updated_text
        except ValueError as e:
            processed = "".join(processed)
            err = e.args[0]
            raise ValueError(f"{processed}\n^^^ {err}")
        except IndexError:
            processed = "".join(processed)
>           raise ValueError(f"{processed}\n^^^ Incomplete ORIGINAL/UPDATED block.")
E           ValueError:
E           No problem! Here are the changes to patch `subprocess.check_output` instead of `subprocess.run` in both tests:
E
E           ```python
E           tests/test_repomap.py
E           <<<<<<< ORIGINAL
E               def test_check_for_ctags_failure(self):
E                   with patch("subprocess.run") as mock_run:
E                       mock_run.side_effect = Exception("ctags not found")
E           =======
E
E           <<<<<<< ORIGINAL
E
E           ^^^ Incomplete ORIGINAL/UPDATED block.

aider/utils.py:259: ValueError
=========================== short test summary info ============================
FAILED tests/test_utils.py::TestUtils::test_false_incomplete_edit_block - Val...
========================= 1 failed, 10 passed in 0.04s =========================

ASSISTANT: It seems that the test `test_false_incomplete_edit_block` is failing due to an IndexError in the `find_original_update_blocks` function in `aider/utils.py`. I will fix the issue by handling the IndexError properly.

```python
aider/utils.py
<<<<<<< ORIGINAL
    if not len(filename) or "`" in filename:
        filename = processed[-2].splitlines()[-2].strip()
        if not len(filename) or "`" in filename:
            raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
=======
    try:
        if not len(filename) or "`" in filename:
            filename = processed[-2].splitlines()[-2].strip()
            if not len(filename) or "`" in filename:
                raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
    except IndexError:
        raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
>>>>>>> UPDATED
```

Now, the IndexError should be handled properly, and the test should pass. Please run the tests again to confirm the fix.
This commit is contained in:
Paul Gauthier 2023-05-29 07:09:09 -07:00
parent a404698a92
commit 87c902b285

View file

@ -230,10 +230,13 @@ def find_original_update_blocks(content):
processed.append(cur) # original_marker
filename = processed[-2].splitlines()[-1].strip()
try:
if not len(filename) or "`" in filename:
filename = processed[-2].splitlines()[-2].strip()
if not len(filename) or "`" in filename:
filename = processed[-2].splitlines()[-2].strip()
if not len(filename) or "`" in filename:
raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
except IndexError:
raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
original_text = pieces.pop()
processed.append(original_text)