File size: 2,951 Bytes
e1f352a
00ea332
e1f352a
00ea332
e1f352a
 
 
4addbf0
e1f352a
4addbf0
 
 
 
e1f352a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
00ea332
 
e1f352a
 
 
4addbf0
 
00ea332
e1f352a
 
 
 
 
00ea332
e1f352a
00ea332
e1f352a
 
 
 
 
 
 
 
00ea332
e1f352a
00ea332
 
e1f352a
 
00ea332
e1f352a
00ea332
e1f352a
 
 
00ea332
e1f352a
 
 
 
 
00ea332
e1f352a
 
00ea332
e1f352a
00ea332
 
 
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
73
74
75
76
77
78
79
80
81
82
83
# app.py
import gradio as gr
import sys, io, traceback, re, subprocess, importlib, multiprocessing, resource, signal

# ----------------------
# Helper: Install missing packages safely
# ----------------------
def _install_missing(packages):
    """Install packages if not already installed. Fail gracefully if not found."""
    for pkg in packages:
        try:
            importlib.import_module(pkg)
        except ImportError:
            try:
                subprocess.check_call(
                    [sys.executable, "-m", "pip", "install", "--disable-pip-version-check", "-q", pkg]
                )
            except subprocess.CalledProcessError:
                # فقط هشدار می‌ده، برنامه نمی‌ترکه
                print(f"[WARN] Package '{pkg}' not found on PyPI or failed to install.", file=sys.stderr)

# ----------------------
# Worker process
# ----------------------
def _worker(code, stdin_input, conn):
    sys.stdin = io.StringIO(stdin_input)
    sys.stdout = io.StringIO()
    sys.stderr = io.StringIO()

    # محدودیت حافظه و زمان
    resource.setrlimit(resource.RLIMIT_AS, (512 * 1024 * 1024, 512 * 1024 * 1024))  # 512MB
    signal.alarm(10)  # 10 ثانیه تایم‌اوت

    try:
        # پیدا کردن importها
        imports = re.findall(r'^\s*import (\w+)|^\s*from (\w+)', code, flags=re.MULTILINE)
        imports = {i[0] or i[1] for i in imports}
        if imports:
            _install_missing(imports)

        safe_globals = {"__builtins__": __builtins__}
        exec(compile(code, "<user_code>", "exec"), safe_globals, None)
        out = sys.stdout.getvalue()
        err = sys.stderr.getvalue()
        conn.send((out, err))
    except Exception:
        conn.send(("", traceback.format_exc()))
    finally:
        conn.close()

# ----------------------
# Runner
# ----------------------
def run_code(code, stdin_input=""):
    parent_conn, child_conn = multiprocessing.Pipe()
    p = multiprocessing.Process(target=_worker, args=(code, stdin_input, child_conn))
    p.start()
    p.join(12)  # یک مقدار بیشتر از تایم‌اوت داخلی
    if p.is_alive():
        p.terminate()
        return "", "Error: Timeout (execution took too long)"
    return parent_conn.recv()

# ----------------------
# Gradio UI
# ----------------------
with gr.Blocks(title="Python Runner (Auto Install)") as demo:
    gr.Markdown("### 🐍 Python Sandbox with Auto-Package Install (USE WITH CAUTION)")

    code = gr.Code(label="Python code", language="python")
    stdin = gr.Textbox(label="stdin", placeholder="Optional input for `input()` calls")
    run_btn = gr.Button("▶ Run")
    stdout = gr.Textbox(label="stdout")
    stderr = gr.Textbox(label="stderr", elem_classes="stderr")

    def execute(c, s):
        return run_code(c, s)

    run_btn.click(execute, [code, stdin], [stdout, stderr])

if __name__ == "__main__":
    demo.launch()