Skip to content

Commit

Permalink
feat: Perform lint repair on generated test code
Browse files Browse the repository at this point in the history
  • Loading branch information
kgilpin committed Aug 3, 2024
1 parent 2eeeb43 commit 4815d12
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 151 deletions.
49 changes: 26 additions & 23 deletions appmap/navie/format_instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,40 @@ def xml_format_instructions():
<file change-number-for-this-file="1">src/myproj/myfunc.py</file>
<original line-count="14" no-ellipsis="true"><![CDATA[
class DateTime(Field):
def bind_to_schema(self, field_name, schema):
self.field_name = field_name
self.container = schema
# Configure format from schema opts
if self.format is None and hasattr(schema, "opts"):
self.format = schema.opts.datetimeformat
self.dateformat = schema.opts.dateformat
self.metadata["marshmallow_field"] = self
# _bind_to_schema is called before processors
if hasattr(schema, "root"):
self.root = schema.root
if self.metadata.get("validate"):
self._validate = self.metadata["validate"]
]]></original>
<modified no-ellipsis="true"><![CDATA[
class DateTime(Field):
def bind_to_schema(self, field_name, schema):
self.field_name = field_name
self.container = schema
# Check if 'schema' has 'opts' before accessing
if hasattr(schema, "opts"):
def bind_to_schema(self, field_name, schema):
self.field_name = field_name
self.container = schema
# Configure format from schema opts
if self.format is None:
if self.format is None and hasattr(schema, "opts"):
self.format = schema.opts.datetimeformat
self.dateformat = schema.opts.dateformat
self.metadata["marshmallow_field"] = self
self.metadata["marshmallow_field"] = self
# _bind_to_schema is called before processors
if hasattr(schema, "root"):
self.root = schema.root
if self.metadata.get("validate"):
self._validate = self.metadata["validate"]
]]></original>
<modified no-ellipsis="true"><![CDATA[
class DateTime(Field):
def bind_to_schema(self, field_name, schema):
self.field_name = field_name
self.container = schema
# Check if 'schema' has 'opts' before accessing
if hasattr(schema, "opts"):
# Configure format from schema opts
if self.format is None:
self.format = schema.opts.datetimeformat
self.dateformat = schema.opts.dateformat
self.metadata["marshmallow_field"] = self
# _bind_to_schema is called before processors
if hasattr(schema, "root"):
self.root = schema.root
if self.metadata.get("validate"):
self._validate = self.metadata["validate"]
def new_method(self):
pass
]]></modified>
</change>
"""
18 changes: 10 additions & 8 deletions appmap/solve/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ def __init__(
self.changed_files_limit = changed_files_limit
self.test_attempts = test_attempts

if self.lint_command and not self.steps["apply"]:
print(
f"[solver] ({self.instance_id}) WARN: Lint command will not be executed without apply step."
)

if not os.path.isfile(self.issue_file):
raise FileNotFoundError(f"File '{self.issue_file}' not found.")

Expand Down Expand Up @@ -168,12 +163,19 @@ def maketest(self):
self.task_manager,
self.issue_file,
self.work_dir,
self.lint_command,
self.test_attempts,
)

maketest_files = [result["test_file"] for result in maketest_results]
self.maketest_errors = [result["error_summary"] for result in maketest_results]
self.extend_test_directives(maketest_files)
results_with_error_summary = [
result for result in maketest_results if "error_summary" in result
]
self.maketest_errors = [
result["error_summary"] for result in results_with_error_summary
]
self.extend_test_directives(
[result["test_directive"] for result in maketest_results]
)

def plan(self):
step_plan(
Expand Down
35 changes: 35 additions & 0 deletions appmap/solve/steps/lint_repair.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import subprocess


# Lint the file and return a dictionary of line numbers with lint errors.
def lint(lint_command: list) -> dict:
lint_result = subprocess.run(
lint_command, capture_output=True, shell=False, text=True
)

lint_output = lint_result.stdout
lint_errors = lint_output.split("\n")

# Lint errors are formatted like this:
# bin/solve.py:257:80: E501 line too long (231 > 79 characters)
# Collect the line numbers of the lint errors.
lint_errors_by_line_number = {}
for error in lint_errors:
if error:
tokens = error.split(":")
if len(tokens) > 1:
line_number = tokens[1]
if line_number and line_number.isdigit():
lint_errors_by_line_number[int(line_number)] = error

return lint_errors_by_line_number


def lint_in_conda(conda_path, conda_env, lint_command, file):
return lint(
[
"bash",
"-c",
f". {conda_path}/bin/activate {conda_env} && {lint_command} {file}",
]
)
59 changes: 15 additions & 44 deletions appmap/solve/steps/step_lint_repair.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from appmap.navie.editor import Editor
from appmap.navie.extract_changes import extract_changes
from ..log import log_diff, log_lint, log_command
from appmap.solve.steps.lint_repair import lint_in_conda
from ..log import log_diff
from ..run_command import run_command
from ..run_navie_command import run_navie_command
from ...navie.format_instructions import xml_format_instructions


import os
import subprocess


class LintRepairContext:
Expand Down Expand Up @@ -58,42 +58,7 @@ def diff_file(context, file, step):
return file_diff


# Lint the file and return a dictionary of line numbers with lint errors
def lint_file(context, file):
lint_args = [
"bash",
"-c",
f". {context.conda_path}/bin/activate {context.conda_env} && {context.lint_command} {file}",
]
log_command(context.log_dir, " ".join(lint_args))

lint_result = subprocess.run(lint_args, capture_output=True, shell=False, text=True)

lint_output = lint_result.stdout

log_lint(
context.log_dir, os.path.join(context.work_dir_base_name, file), lint_output
)

lint_errors = lint_output.split("\n")

# Lint errors are formatted like this:
# bin/solve.py:257:80: E501 line too long (231 > 79 characters)
# Collect the line numbers of the lint errors.
lint_errors_by_line_number = {}
for error in lint_errors:
if error:
tokens = error.split(":")
if len(tokens) > 1:
line_number = tokens[1]
if line_number and line_number.isdigit():
lint_errors_by_line_number[int(line_number)] = error
return lint_errors_by_line_number


def lint_error_line_numbers_within_diff_sections(
file, lint_errors_by_line_number, file_diff
):
def lint_error_line_numbers_within_diff_sections(lint_errors_by_line_number, file_diff):
# The file diff contains chunks like:
# @@ -147,15 +147,21 @@
# Find the '+' number, which indicates the start line. Also find the number after the
Expand Down Expand Up @@ -143,18 +108,22 @@ def step_lint_repair(

print(f"[lint-repair] ({instance_id}) Linting {file}")

lint_errors_by_line_number = lint_file(context, file)
lint_errors_by_line_number = lint_in_conda(
context.conda_path, context.conda_env, context.lint_command, file
)
if not len(lint_errors_by_line_number):
print(f"[lint-repair] ({instance_id}) No lint errors found in {file}")
continue

lint_errors = "\n".join(lint_errors_by_line_number.values())
print(lint_errors)
print(
f"[lint-repair] ({instance_id}) Lint errors found in {file}: {lint_errors}"
)

file_diff = diff_file(context, file, "pre")

line_numbers = lint_error_line_numbers_within_diff_sections(
file, lint_errors_by_line_number, file_diff
lint_errors_by_line_number, file_diff
)

if line_numbers:
Expand Down Expand Up @@ -320,13 +289,15 @@ def step_lint_repair(
)
repair_item += 1

post_fix_lint_errors_by_line_number = lint_file(context, file)
post_fix_lint_errors_by_line_number = lint_in_conda(
context.conda_path, context.conda_env, context.lint_command, file
)
post_file_diff = diff_file(context, file, "post")

print(post_file_diff)
print(f"[lint-repair] ({instance_id}) Diff after repair:\n{post_file_diff}")

post_line_numbers = lint_error_line_numbers_within_diff_sections(
file, post_fix_lint_errors_by_line_number, post_file_diff
post_fix_lint_errors_by_line_number, post_file_diff
)

if post_line_numbers:
Expand Down
Loading

0 comments on commit 4815d12

Please sign in to comment.