Skip to content

Commit 973ccac

Browse files
committed
Fix remaining ruff linting errors (including unsafe fixes)
1 parent 5f877d5 commit 973ccac

4 files changed

Lines changed: 44 additions & 45 deletions

File tree

app.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ async def heal(payload: IssuePayload):
6161
status_code=status.HTTP_404_NOT_FOUND,
6262
detail=f"Target file not found at path: {payload.file_path}"
6363
)
64-
64+
6565
task_id = uuid.uuid4().hex
6666
tasks_db[task_id] = {
6767
"status": "PENDING",
@@ -91,19 +91,19 @@ async def heal_auto(mode: str = "script", file_path: str = None):
9191
status_code=status.HTTP_400_BAD_REQUEST,
9292
detail="Invalid mode. Must be 'script' or 'pytest'."
9393
)
94-
94+
9595
if not file_path:
9696
if mode == "pytest":
9797
file_path = "tests/test_mock_code.py"
9898
else:
9999
file_path = "tests/mock_run.py"
100-
100+
101101
if not os.path.exists(file_path):
102102
raise HTTPException(
103103
status_code=status.HTTP_404_NOT_FOUND,
104104
detail=f"Target file not found at path: {file_path}"
105105
)
106-
106+
107107
task_id = uuid.uuid4().hex
108108
tasks_db[task_id] = {
109109
"status": "PENDING",

main.py

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import asyncio
55
import argparse
66
from dotenv import load_dotenv
7-
from pydantic import ValidationError
87

98
from schemas import IssuePayload
109
from parser import extract_function_source, replace_function_source
@@ -21,15 +20,15 @@ def clean_agent_code(response_text: str, function_name: str) -> str:
2120
code = code[3:].strip()
2221
if code.endswith("```"):
2322
code = code[:-3].strip()
24-
23+
2524
def_prefix = f"def {function_name}"
2625
if def_prefix in code:
2726
idx = code.find(def_prefix)
2827
code = code[idx:]
29-
28+
3029
if code.endswith("```"):
3130
code = code[:-3].strip()
32-
31+
3332
return code
3433

3534
async def run_pytest_suite(test_file: str) -> tuple[int, str]:
@@ -38,15 +37,15 @@ async def run_pytest_suite(test_file: str) -> tuple[int, str]:
3837
python_exe = os.path.join(".venv", "Scripts", "python.exe")
3938
else:
4039
python_exe = os.path.join(".venv", "bin", "python")
41-
40+
4241
if not os.path.exists(python_exe):
4342
python_exe = sys.executable
4443

4544
cmd = [python_exe, "-m", "pytest", test_file]
46-
45+
4746
env = os.environ.copy()
4847
env["PYTHONPATH"] = os.getcwd()
49-
48+
5049
process = await asyncio.create_subprocess_exec(
5150
*cmd,
5251
stdout=asyncio.subprocess.PIPE,
@@ -64,15 +63,15 @@ async def run_script_file(script_file: str) -> tuple[int, str]:
6463
python_exe = os.path.join(".venv", "Scripts", "python.exe")
6564
else:
6665
python_exe = os.path.join(".venv", "bin", "python")
67-
66+
6867
if not os.path.exists(python_exe):
6968
python_exe = sys.executable
7069

7170
cmd = [python_exe, script_file]
72-
71+
7372
env = os.environ.copy()
7473
env["PYTHONPATH"] = os.getcwd()
75-
74+
7675
process = await asyncio.create_subprocess_exec(
7776
*cmd,
7877
stdout=asyncio.subprocess.PIPE,
@@ -92,13 +91,13 @@ def parse_python_traceback(traceback_text: str) -> tuple[str, str, str]:
9291
lines = traceback_text.splitlines()
9392
if not lines:
9493
raise ValueError("Empty output, no traceback found.")
95-
94+
9695
error_message = lines[-1].strip()
9796
file_path = None
9897
function_name = None
99-
98+
10099
traceback_re = re.compile(r'^\s*File\s+"([^"]+)",\s+line\s+(\d+),\s+in\s+(\w+)')
101-
100+
102101
for i in range(len(lines) - 2, -1, -1):
103102
match = traceback_re.match(lines[i])
104103
if match:
@@ -108,10 +107,10 @@ def parse_python_traceback(traceback_text: str) -> tuple[str, str, str]:
108107
file_path = match.group(1).replace("\\", "/")
109108
function_name = func
110109
break
111-
110+
112111
if not file_path or not function_name:
113112
raise ValueError("Could not extract file path or function name from Python traceback.")
114-
113+
115114
return file_path, function_name, error_message
116115

117116
def parse_pytest_failure(pytest_output: str) -> tuple[str, str, str]:
@@ -122,43 +121,43 @@ def parse_pytest_failure(pytest_output: str) -> tuple[str, str, str]:
122121
lines = pytest_output.splitlines()
123122
if not lines:
124123
raise ValueError("Empty output, no pytest logs found.")
125-
124+
126125
file_path = None
127126
function_name = None
128127
error_log = []
129-
128+
130129
file_line_err_re = re.compile(r"^([a-zA-Z0-9_\-\/\\\. ]+\.py):(\d+): (\w+)")
131-
130+
132131
for i in range(len(lines) - 1, -1, -1):
133132
line = lines[i].strip()
134133
match = file_line_err_re.match(line)
135134
if match:
136135
possible_file = match.group(1).replace("\\", "/")
137136
if "test_" in os.path.basename(possible_file):
138137
continue
139-
138+
140139
file_path = possible_file
141-
140+
142141
for j in range(i, -1, -1):
143142
if lines[j].strip().startswith("E "):
144143
error_log.append(lines[j].strip()[4:])
145144
break
146145
if not error_log:
147146
error_log.append(line)
148-
147+
149148
func_def_re = re.compile(r"^\s*def\s+(\w+)\s*\(")
150149
for j in range(i, -1, -1):
151150
m = func_def_re.match(lines[j])
152151
if m:
153152
function_name = m.group(1)
154153
break
155-
154+
156155
if file_path and function_name:
157156
break
158-
157+
159158
if not file_path or not function_name:
160159
raise ValueError("Could not auto-detect buggy file or function from pytest output.")
161-
160+
162161
return file_path, function_name, "\n".join(error_log)
163162

164163
async def heal_once(payload: IssuePayload) -> None:
@@ -190,7 +189,7 @@ async def heal_once(payload: IssuePayload) -> None:
190189
raise ValueError(err_msg)
191190

192191
print(f"Original source extracted successfully:\n---\n{func_source}\n---")
193-
192+
194193
prompt = f"""
195194
Original function code:
196195
```python
@@ -204,7 +203,7 @@ async def heal_once(payload: IssuePayload) -> None:
204203
205204
Please correct the function to make the execution/tests pass. Remember, return ONLY the corrected function definition.
206205
"""
207-
206+
208207
print("Sending prompt to Gemini via google.antigravity.Agent...")
209208
try:
210209
async with Agent(config) as agent:
@@ -239,20 +238,20 @@ async def auto_heal_code(run_target: str, mode: str = "script", max_attempts: in
239238
print("=" * 60)
240239
print(f"Starting Auto-Heal Loop for target: '{run_target}' in mode: '{mode}'")
241240
print("=" * 60)
242-
241+
243242
for attempt in range(1, max_attempts + 1):
244243
print(f"\n[Auto-Heal Attempt {attempt}/{max_attempts}] Running target...")
245244
if mode == "pytest":
246245
exit_code, output = await run_pytest_suite(run_target)
247246
else:
248247
exit_code, output = await run_script_file(run_target)
249-
248+
250249
if exit_code == 0:
251250
print("\n" + "*" * 60)
252251
print("SUCCESS: Target executed successfully with no errors!")
253252
print("*" * 60)
254253
return True
255-
254+
256255
print("Execution failed. Parsing traceback to auto-detect target...")
257256
try:
258257
if mode == "pytest":
@@ -263,8 +262,8 @@ async def auto_heal_code(run_target: str, mode: str = "script", max_attempts: in
263262
print(f"Failed to auto-detect bug: {e}")
264263
print(f"Raw Target Output:\n{output}")
265264
raise ValueError(f"Could not auto-detect buggy code: {e}")
266-
267-
print(f"Auto-Detected Bug Details:")
265+
266+
print("Auto-Detected Bug Details:")
268267
print(f" File Path: {file_path}")
269268
print(f" Function Name: {function_name}")
270269
print(f" Error Message: {error_msg}")
@@ -275,10 +274,10 @@ async def auto_heal_code(run_target: str, mode: str = "script", max_attempts: in
275274
)
276275
print(f"Triggering repair for function '{function_name}'...")
277276
await heal_once(payload)
278-
277+
279278
print("Pausing for 8 seconds to stay under the API rate limit...")
280279
await asyncio.sleep(8)
281-
280+
282281
print("\n" + "!" * 60)
283282
err_msg = f"Could not heal all errors after {max_attempts} attempts. Last output:\n{output}"
284283
print(err_msg)

parser.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33

44
def extract_function_source(file_path: str, function_name: str) -> str:
55
"""
6-
Parses the file at file_path into an AST, finds the FunctionDef node
6+
Parses the file at file_path into an AST, finds the FunctionDef node
77
matching function_name, and returns its raw source code block.
88
"""
99
with open(file_path, "r", encoding="utf-8") as f:
1010
source_code = f.read()
1111

1212
tree = ast.parse(source_code)
13-
13+
1414
for node in ast.walk(tree):
1515
if isinstance(node, ast.FunctionDef) and node.name == function_name:
1616
source_segment = ast.get_source_segment(source_code, node)
@@ -23,24 +23,24 @@ def extract_function_source(file_path: str, function_name: str) -> str:
2323

2424
def adjust_indentation(code: str, target_indent_spaces: int) -> str:
2525
"""
26-
Dedents the input code first, then indents non-empty lines to match
26+
Dedents the input code first, then indents non-empty lines to match
2727
the target_indent_spaces level.
2828
"""
2929
dedented = textwrap.dedent(code)
3030
return textwrap.indent(dedented, " " * target_indent_spaces)
3131

3232
def replace_function_source(file_path: str, function_name: str, new_source_code: str) -> None:
3333
"""
34-
Locates the FunctionDef node in the source file, calculates its line range,
35-
replaces it with the new healed function code matching the original
34+
Locates the FunctionDef node in the source file, calculates its line range,
35+
replaces it with the new healed function code matching the original
3636
indentation level, and writes the updated contents back to disk.
3737
"""
3838
with open(file_path, "r", encoding="utf-8") as f:
3939
source_code = f.read()
4040

4141
tree = ast.parse(source_code)
4242
target_node = None
43-
43+
4444
for node in ast.walk(tree):
4545
if isinstance(node, ast.FunctionDef) and node.name == function_name:
4646
target_node = node
@@ -58,7 +58,7 @@ def replace_function_source(file_path: str, function_name: str, new_source_code:
5858

5959
# Split original code by lines to do line-range replacement
6060
lines = source_code.splitlines(keepends=True)
61-
61+
6262
# ast line numbers are 1-indexed
6363
start_idx = target_node.lineno - 1
6464
end_idx = target_node.end_lineno

schemas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
class IssuePayload(BaseModel):
44
"""Pydantic model representing the incoming bug report payload."""
5-
5+
66
model_config = {
77
"extra": "forbid",
88
"str_strip_whitespace": True,

0 commit comments

Comments
 (0)