Skip to content

Commit

Permalink
- reorganized gpt-v2 prompts to allow ablating individual features;
Browse files Browse the repository at this point in the history
  • Loading branch information
jaltmayerpizzorno committed Jan 27, 2025
1 parent 681f499 commit ee935a0
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 173 deletions.
14 changes: 8 additions & 6 deletions src/coverup/coverup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@ def get_prompters() -> dict[str, Prompter]:

from .prompt.gpt_v1 import GptV1Prompter
from .prompt.gpt_v2 import GptV2Prompter
from .prompt.gpt_v2_no_coverage import GptV2NoCoveragePrompter
from .prompt.gpt_v2_no_coverage_no_function import GptV2NoCoverageNoFunctionPrompter
from .prompt.gpt_v2_fully_ablated import GptV2FullyAblatedPrompter
from .prompt.gpt_v2_ablated import GptV2AblatedPrompter
from .prompt.claude import ClaudePrompter

return {
"gpt-v1": GptV1Prompter,
"gpt-v2": GptV2Prompter,
"gpt-v2-no-coverage": GptV2NoCoveragePrompter,
"gpt-v2-no-coverage-no-function": GptV2NoCoverageNoFunctionPrompter,
"gpt-v2-fully-ablated": GptV2FullyAblatedPrompter,
"gpt-v2-no-coverage": lambda cmd_args: GptV2AblatedPrompter(cmd_args, with_coverage=False),
"gpt-v2-no-get-info": lambda cmd_args: GptV2AblatedPrompter(cmd_args, with_get_info=False),
"gpt-v2-no-imports": lambda cmd_args: GptV2AblatedPrompter(cmd_args, with_imports=False),
"gpt-v2-no-error-fixing": lambda cmd_args: GptV2AblatedPrompter(cmd_args, with_error_fixing=False),
"gpt-v2-ablated": \
lambda cmd_args: GptV2AblatedPrompter(cmd_args,
with_coverage=False, with_get_info=False, with_imports=False, with_error_fixing=False),
"claude": ClaudePrompter
}

Expand Down
80 changes: 80 additions & 0 deletions src/coverup/prompt/gpt_v2_ablated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import typing as T
from .gpt_v2 import *


class GptV2AblatedPrompter(GptV2Prompter):
"""Prompter for GPT 4."""

def __init__(
self,
cmd_args,
*,
with_coverage: bool = True,
with_get_info: bool = True,
with_imports: bool = True,
with_error_fixing: bool = True
):
super().__init__(cmd_args)
self.with_coverage = with_coverage
self.with_get_info = with_get_info
self.with_imports = with_imports
self.with_error_fixing = with_error_fixing


def initial_prompt(self, segment: CodeSegment) -> T.List[dict]:
module_name = get_module_name(segment.path, self.args.package_dir)
filename = segment.path.relative_to(self.args.package_dir.parent)

return [
mk_message(f"""
You are an expert Python test-driven developer.
""" + (f"""\
The code below, extracted from {filename}, does not achieve full coverage:
when tested, {segment.lines_branches_missing_do()} not execute.
Create new pytest test functions that execute all missing lines and branches, always making
""" if self.with_coverage else f"""\
The code below, extracted from {filename}, does not achieve full coverage.
Create new pytest test functions that execute all lines and branches, always making
""") + f"""\
sure that each test is correct and indeed improves coverage.
""" + ("Use the get_info tool function as necessary.\n" if self.with_get_info else "") + f"""\
Always send entire Python test scripts when proposing a new test or correcting one you
previously proposed.
Be sure to include assertions in the test that verify any applicable postconditions.
Please also make VERY SURE to clean up after the test, so as to avoid state pollution;
use 'monkeypatch' or 'pytest-mock' if appropriate.
Write as little top-level code as possible, and in particular do not include any top-level code
calling into pytest.main or the test itself.
Respond ONLY with the Python code enclosed in backticks, without any explanation.
```python
{segment.get_excerpt(tag_lines=self.with_coverage, add_imports=self.with_imports)}
```
""")
]


def error_prompt(self, segment: CodeSegment, error: str) -> T.List[dict] | None:
if not self.with_error_fixing: return None
return [mk_message(f"""\
Executing the test yields an error, shown below.
Modify or rewrite the test to correct it; respond only with the complete Python code in backticks.
""" + ("Use the get_info tool function as necessary.\n" if self.with_get_info else "") + f"""\
{error}""")
]


def missing_coverage_prompt(self, segment: CodeSegment,
missing_lines: set, missing_branches: set) -> T.List[dict]:
if not self.with_coverage: return None
return [mk_message(f"""\
The tests still lack coverage: {lines_branches_do(missing_lines, set(), missing_branches)} not execute.
Modify it to correct that; respond only with the complete Python code in backticks.
""" + ("Use the get_info tool function as necessary.\n" if self.with_get_info else "")
)
]


def get_functions(self) -> T.List[T.Callable]:
if not self.with_get_info: return []
return [__class__.get_info]
15 changes: 12 additions & 3 deletions src/coverup/prompt/gpt_v2_fully_ablated.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import typing as T
from .gpt_v2_no_coverage_no_function import *
from .gpt_v2 import *


class GptV2FullyAblatedPrompter(GptV2NoCoverageNoFunctionPrompter):
class GptV2FullyAblatedPrompter(GptV2Prompter):
"""Fully ablated GPT prompter."""

def __init__(self, *args, **kwargs):
Expand All @@ -28,11 +28,20 @@ def initial_prompt(self, segment: CodeSegment) -> T.List[dict]:
calling into pytest.main or the test itself.
Respond ONLY with the Python code enclosed in backticks, without any explanation.
```python
{segment.get_excerpt(tag_lines=False, include_imports=False)}
{segment.get_excerpt(tag_lines=False, add_imports=False)}
```
""")
]


def error_prompt(self, segment: CodeSegment, error: str) -> T.List[dict] | None:
return None


def missing_coverage_prompt(self, segment: CodeSegment,
missing_lines: set, missing_branches: set) -> T.List[dict] | None:
return None


def get_functions(self) -> T.List[T.Callable]:
return []
42 changes: 0 additions & 42 deletions src/coverup/prompt/gpt_v2_no_coverage.py

This file was deleted.

39 changes: 0 additions & 39 deletions src/coverup/prompt/gpt_v2_no_coverage_no_function.py

This file was deleted.

4 changes: 2 additions & 2 deletions src/coverup/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ def identify(self) -> str:
def __str__(self) -> str:
return self.identify()

def get_excerpt(self, tag_lines=True, include_imports=True):
def get_excerpt(self, *, tag_lines=True, add_imports=True):
excerpt = []
with open(self.filename, "r") as src:
code = src.readlines()

if include_imports:
if add_imports:
for imp in self.imports:
excerpt.extend([f"{'':10} {imp}\n"])

Expand Down
19 changes: 0 additions & 19 deletions tests/test_coverup_1.py

This file was deleted.

25 changes: 0 additions & 25 deletions tests/test_coverup_9.py

This file was deleted.

Loading

0 comments on commit ee935a0

Please sign in to comment.