from fastapi import FastAPI, Request, Form from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates import sys import io app = FastAPI() templates = Jinja2Templates(directory="templates") # --- Core tracer logic --- def run_code_with_trace(code: str): trace_data = [] stdout_capture = io.StringIO() def tracer(frame, event, arg): if event == "line": trace_data.append({ "line": frame.f_lineno, "locals": frame.f_locals.copy() }) return tracer sys.settrace(tracer) try: exec(code, {}, {}) except Exception as e: trace_data.append({"error": str(e)}) finally: sys.settrace(None) output = stdout_capture.getvalue() stdout_capture.close() return trace_data, output @app.get("/", response_class=HTMLResponse) async def index(request: Request): return templates.TemplateResponse("index.html", {"request": request}) @app.post("/run", response_class=HTMLResponse) async def run_code(request: Request, code: str = Form(...)): trace, output = run_code_with_trace(code) return templates.TemplateResponse( "index.html", { "request": request, "trace": trace, "output": output, "code": code } )