File size: 2,063 Bytes
079a804
511a6d9
a310d13
079a804
 
 
a310d13
079a804
 
0944f07
 
a310d13
079a804
 
0944f07
079a804
 
 
 
0944f07
 
 
 
 
 
 
 
 
079a804
 
0944f07
079a804
 
0944f07
079a804
 
 
0944f07
079a804
0944f07
079a804
0944f07
 
079a804
 
 
 
0944f07
079a804
 
 
 
 
0944f07
079a804
 
 
 
0944f07
079a804
 
 
 
 
 
 
a310d13
079a804
 
 
b87b24a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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()

# Mount static files (for CSS, JS)
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()

    # ✅ Safely serialize objects (avoid JSON TypeError)
    def safe_serialize(obj):
        try:
            json.dumps(obj)
            return obj
        except (TypeError, OverflowError):
            return str(obj)

    # ✅ Tracer function
    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

    # Redirect stdout temporarily (if user uses print)
    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__  # reset 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
        }
    )