| | from fastapi import FastAPI, Request, Form |
| | from fastapi.responses import HTMLResponse |
| | from fastapi.staticfiles import StaticFiles |
| | from fastapi.templating import Jinja2Templates |
| | import sys |
| | import io |
| | import json |
| |
|
| | app = FastAPI() |
| |
|
| | |
| | app.mount("/static", StaticFiles(directory="static"), name="static") |
| | templates = Jinja2Templates(directory="templates") |
| |
|
| |
|
| | def run_code_with_trace(code: str): |
| | trace_data = [] |
| | stdout_capture = io.StringIO() |
| |
|
| | |
| | def safe_serialize(obj): |
| | try: |
| | json.dumps(obj) |
| | return obj |
| | except (TypeError, OverflowError): |
| | return str(obj) |
| |
|
| | |
| | def tracer(frame, event, arg): |
| | if event == "line": |
| | locals_serialized = {k: safe_serialize(v) for k, v in frame.f_locals.items()} |
| | trace_data.append({ |
| | "line": frame.f_lineno, |
| | "locals": locals_serialized |
| | }) |
| | return tracer |
| |
|
| | |
| | sys.settrace(tracer) |
| | sys.stdout = stdout_capture |
| | try: |
| | safe_globals = {"__builtins__": {"print": print, "range": range, "len": len}} |
| | exec(code, safe_globals) |
| | except Exception as e: |
| | trace_data.append({"error": str(e)}) |
| | finally: |
| | sys.settrace(None) |
| | sys.stdout = sys.__stdout__ |
| |
|
| | 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_json": json.dumps(trace), |
| | "output": output, |
| | "code": code |
| | } |
| | ) |
| |
|