codefixer / app.py
HARISARAVANANM's picture
Create app.py
1c358fd verified
import gradio as gr
import ast, traceback, sys, io
import subprocess, tempfile, os
# ── Python static analysis ──────────────────────────────────────────────────
def analyze_python(code: str):
errors = []
warnings = []
# 1. Syntax check via ast
try:
tree = ast.parse(code)
except SyntaxError as e:
errors.append(f"SyntaxError (line {e.lineno}): {e.msg}")
return errors, warnings, tree if 'tree' in dir() else None
# 2. Walk AST for common issues
for node in ast.walk(tree):
# Bare except
if isinstance(node, ast.ExceptHandler) and node.type is None:
warnings.append(f"Line {node.lineno}: Bare `except:` β€” catch specific exceptions instead.")
# == None instead of is None
if isinstance(node, ast.Compare):
for op, comp in zip(node.ops, node.comparators):
if isinstance(op, (ast.Eq, ast.NotEq)) and isinstance(comp, ast.Constant) and comp.value is None:
warnings.append(f"Line {node.lineno}: Use `is None` / `is not None` instead of `== None`.")
# Mutable default argument
if isinstance(node, ast.FunctionDef):
for default in node.args.defaults:
if isinstance(default, (ast.List, ast.Dict, ast.Set)):
warnings.append(f"Line {node.lineno}: Mutable default argument in `{node.name}()` β€” use None instead.")
# Undefined names (basic)
if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load):
pass # would need scope tracking β€” skipped for simplicity
return errors, warnings, tree
def run_python(code: str):
"""Safely run code in a subprocess with timeout."""
try:
with tempfile.NamedTemporaryFile(suffix=".py", mode="w", delete=False) as f:
f.write(code)
fname = f.name
result = subprocess.run(
[sys.executable, fname],
capture_output=True, text=True, timeout=5
)
os.unlink(fname)
stdout = result.stdout.strip()
stderr = result.stderr.strip()
return stdout, stderr
except subprocess.TimeoutExpired:
return "", "⏱️ Execution timed out (5s limit)."
except Exception as e:
return "", str(e)
def analyze_javascript(code: str):
"""Basic JS pattern checks."""
errors, warnings = [], []
lines = code.split("\n")
for i, line in enumerate(lines, 1):
s = line.strip()
if s.startswith("var "):
warnings.append(f"Line {i}: Use `let` or `const` instead of `var`.")
if "==" in s and "===" not in s and "!==" not in s:
warnings.append(f"Line {i}: Use `===` instead of `==` for strict equality.")
if "eval(" in s:
errors.append(f"Line {i}: Avoid `eval()` β€” security risk.")
if s.endswith("{") is False and s and not s.startswith("//") and not s.endswith(";") and not s.endswith("{") and not s.endswith("}") and not s.endswith(","):
pass # too noisy to flag missing semicolons
return errors, warnings
def check_code(code, language):
if not code.strip():
return "❌ Please paste some code first."
result_parts = []
if language == "Python":
errors, warnings, _ = analyze_python(code)
stdout, stderr = run_python(code)
if errors:
result_parts.append("### πŸ”΄ Errors\n" + "\n".join(f"- {e}" for e in errors))
if stderr:
result_parts.append("### πŸ”΄ Runtime Error\n```\n" + stderr + "\n```")
if warnings:
result_parts.append("### 🟑 Warnings\n" + "\n".join(f"- {w}" for w in warnings))
if stdout:
result_parts.append("### βœ… Output\n```\n" + stdout + "\n```")
if not errors and not warnings and not stderr:
result_parts.append("### βœ… No issues found!\nCode looks clean.")
elif language == "JavaScript":
errors, warnings = analyze_javascript(code)
if errors:
result_parts.append("### πŸ”΄ Errors\n" + "\n".join(f"- {e}" for e in errors))
if warnings:
result_parts.append("### 🟑 Warnings\n" + "\n".join(f"- {w}" for w in warnings))
if not errors and not warnings:
result_parts.append("### βœ… No issues found!\nCode looks clean.")
else:
result_parts.append("ℹ️ Basic analysis only for this language.\nPaste your code and check manually for syntax issues.")
return "\n\n".join(result_parts)
def suggest_fix(code, language, analysis_result):
"""Rule-based fix suggestions."""
if not code.strip():
return "Paste code first."
fixes = []
if language == "Python":
fixed = code
if "except:" in fixed:
fixed = fixed.replace("except:", "except Exception as e:")
fixes.append("- Replaced bare `except:` with `except Exception as e:`")
if "== None" in fixed:
fixed = fixed.replace("== None", "is None")
fixes.append("- Replaced `== None` with `is None`")
if "!= None" in fixed:
fixed = fixed.replace("!= None", "is not None")
fixes.append("- Replaced `!= None` with `is not None`")
if fixes:
return "### πŸ”§ Auto-Fixed Code\n```python\n" + fixed + "\n```\n\n**Changes made:**\n" + "\n".join(fixes)
return "### βœ… No automatic fixes needed.\nReview warnings manually."
elif language == "JavaScript":
fixed = code
if "var " in fixed:
fixed = fixed.replace("var ", "let ")
fixes.append("- Replaced `var` with `let`")
if fixes:
return "### πŸ”§ Auto-Fixed Code\n```javascript\n" + fixed + "\n```\n\n**Changes made:**\n" + "\n".join(fixes)
return "### βœ… No automatic fixes needed."
return "Auto-fix not available for this language."
with gr.Blocks(title="Code Error Finder", theme=gr.themes.Soft()) as app:
gr.Markdown("# πŸ› Code Error Finder & Fixer\nPaste code β†’ detect errors β†’ get fix suggestions.")
with gr.Row():
with gr.Column(scale=2):
language = gr.Dropdown(
choices=["Python", "JavaScript", "Other"],
value="Python",
label="Language"
)
code_input = gr.Code(label="Paste Your Code", language="python", lines=20)
with gr.Column(scale=2):
analysis_out = gr.Markdown(label="Analysis Result")
fix_out = gr.Markdown(label="Fix Suggestions")
with gr.Row():
check_btn = gr.Button("πŸ” Analyze Code", variant="primary")
fix_btn = gr.Button("πŸ”§ Suggest Fix", variant="secondary")
check_btn.click(check_code, inputs=[code_input, language], outputs=analysis_out)
fix_btn.click(suggest_fix, inputs=[code_input, language, analysis_out], outputs=fix_out)
gr.Examples(
examples=[
["x = None\nif x == None:\n print('is none')\n\ntry:\n y = 1/0\nexcept:\n pass", "Python"],
["var x = 5;\nif (x == '5') {\n console.log('equal');\n}", "JavaScript"],
],
inputs=[code_input, language]
)
app.launch()