Argus-Backend / core /tools.py
janakb's picture
initial: argus backend
b48421e
Raw
History Blame Contribute Delete
2.98 kB
"""
core/tools.py — Static analysis tools (zero LLM API calls).
"""
import ast
import json
import os
import subprocess
import tempfile
from langchain_core.tools import tool
from radon.complexity import cc_rank, cc_visit
@tool
def flake8_tool(code: str) -> str:
"""Runs flake8 linter on Python code. Returns violations as JSON."""
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write(code)
tmp_path = f.name
try:
result = subprocess.run(
["flake8", "--format=%(row)d::%(col)d::%(code)s::%(text)s", tmp_path],
capture_output=True, text=True,
)
violations = []
for line in result.stdout.strip().splitlines():
parts = line.split("::")
if len(parts) == 4:
violations.append({
"line": int(parts[0].split(":")[-1]),
"col": int(parts[1]),
"code": parts[2],
"message": parts[3],
})
return json.dumps(violations)
finally:
os.unlink(tmp_path)
@tool
def radon_tool(code: str) -> str:
"""Analyzes cyclomatic complexity. Returns per-function scores as JSON."""
try:
return json.dumps([
{
"name": b.name,
"line": b.lineno,
"complexity": b.complexity,
"rank": cc_rank(b.complexity),
"is_high_risk": b.complexity > 5,
}
for b in cc_visit(code)
])
except Exception as exc:
return json.dumps({"error": str(exc)})
@tool
def ast_tool(code: str) -> str:
"""Parses Python AST. Returns functions, classes, imports as JSON."""
try:
tree = ast.parse(code)
functions, classes, imports = [], [], []
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
functions.append({
"name": node.name,
"line": node.lineno,
"args": [a.arg for a in node.args.args],
"has_docstring": ast.get_docstring(node) is not None,
})
elif isinstance(node, ast.ClassDef):
classes.append({
"name": node.name,
"line": node.lineno,
"has_docstring": ast.get_docstring(node) is not None,
})
elif isinstance(node, ast.Import):
for alias in node.names:
imports.append(alias.name)
elif isinstance(node, ast.ImportFrom):
imports.append(
f"from {node.module} import {', '.join(a.name for a in node.names)}"
)
return json.dumps({"functions": functions, "classes": classes, "imports": imports})
except SyntaxError as exc:
return json.dumps({"error": str(exc)})
TOOLS = [flake8_tool, radon_tool, ast_tool]