suprimedev commited on
Commit
e1f352a
·
verified ·
1 Parent(s): 490829e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -151
app.py CHANGED
@@ -1,176 +1,82 @@
1
- import io
2
- import sys
3
- import time
4
- import ast
5
- import traceback
6
- import importlib
7
- import subprocess
8
- from multiprocessing import Process, Queue
9
-
10
- try:
11
- import resource # Linux only (Hugging Face Spaces)
12
- except Exception:
13
- resource = None
14
-
15
  import gradio as gr
 
16
 
17
- # -----------------------------
18
- # Sandbox utilities
19
- # -----------------------------
20
- SAFE_BUILTINS = {
21
- "abs": abs, "all": all, "any": any, "bool": bool, "bytes": bytes, "callable": callable,
22
- "chr": chr, "complex": complex, "dict": dict, "dir": dir, "divmod": divmod,
23
- "enumerate": enumerate, "filter": filter, "float": float, "format": format,
24
- "hash": hash, "help": help, "hex": hex, "int": int, "isinstance": isinstance,
25
- "issubclass": issubclass, "iter": iter, "len": len, "list": list, "map": map,
26
- "max": max, "min": min, "next": next, "object": object, "oct": oct, "ord": ord,
27
- "pow": pow, "print": print, "range": range, "repr": repr, "reversed": reversed,
28
- "round": round, "set": set, "slice": slice, "sorted": sorted, "str": str,
29
- "sum": sum, "tuple": tuple, "type": type, "zip": zip,
30
- "__import__": __import__, # ✅ لازم برای import
31
- }
32
-
33
-
34
- def _parse_imports(code: str) -> list:
35
- """Parse AST and return list of imports found in code."""
36
- try:
37
- tree = ast.parse(code, mode="exec")
38
- except SyntaxError as e:
39
- raise ValueError(f"SyntaxError: {e}")
40
-
41
- imports = []
42
- for node in ast.walk(tree):
43
- if isinstance(node, (ast.Import, ast.ImportFrom)):
44
- for alias in node.names:
45
- pkg = alias.name.split(".")[0]
46
- imports.append(pkg)
47
- return list(set(imports))
48
-
49
-
50
  def _install_missing(packages):
51
- """Install packages if not already installed."""
52
  for pkg in packages:
53
  try:
54
  importlib.import_module(pkg)
55
  except ImportError:
56
- subprocess.check_call([sys.executable, "-m", "pip", "install", pkg])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
-
59
- def _apply_limits(mem_mb: int, cpu_seconds: int):
60
- if resource is None:
61
- return
62
- if mem_mb and mem_mb > 0:
63
- bytes_limit = int(mem_mb) * 1024 * 1024
64
- resource.setrlimit(resource.RLIMIT_AS, (bytes_limit, bytes_limit))
65
- if cpu_seconds and cpu_seconds > 0:
66
- resource.setrlimit(resource.RLIMIT_CPU, (cpu_seconds, cpu_seconds))
67
-
68
-
69
- def _worker(code: str, stdin_data: str, mem_limit_mb: int, cpu_limit_s: int, q: Queue):
70
- stdout_buf, stderr_buf = io.StringIO(), io.StringIO()
71
- start = time.time()
72
  try:
73
- _apply_limits(mem_limit_mb, cpu_limit_s)
74
-
75
- # Redirect streams
76
- orig_stdout, orig_stderr, orig_stdin = sys.stdout, sys.stderr, sys.stdin
77
- sys.stdout, sys.stderr, sys.stdin = stdout_buf, stderr_buf, io.StringIO(stdin_data or "")
78
-
79
- # Install missing packages if needed
80
- imports = _parse_imports(code)
81
  if imports:
82
  _install_missing(imports)
83
 
84
- safe_globals = {"__builtins__": SAFE_BUILTINS}
85
-
86
- exec(compile(code, filename="<user_code>", mode="exec"), safe_globals, None)
87
-
 
88
  except Exception:
89
- traceback.print_exc(file=stderr_buf)
90
  finally:
91
- try:
92
- sys.stdout, sys.stderr, sys.stdin = orig_stdout, orig_stderr, orig_stdin
93
- except Exception:
94
- pass
95
- elapsed = time.time() - start
96
- q.put({
97
- "stdout": stdout_buf.getvalue(),
98
- "stderr": stderr_buf.getvalue(),
99
- "elapsed": elapsed,
100
- })
101
-
102
-
103
- def run_code(code: str, stdin_data: str = "", timeout_s: float = 5.0, mem_limit_mb: int = 512):
104
- q: Queue = Queue()
105
- p = Process(target=_worker, args=(code, stdin_data, int(mem_limit_mb), int(max(1, timeout_s)), q))
106
  p.start()
107
- p.join(timeout=timeout_s)
108
-
109
  if p.is_alive():
110
  p.terminate()
111
- try: p.join(1)
112
- except Exception: pass
113
- return "", "Execution timed out.", timeout_s
114
-
115
- try:
116
- result = q.get_nowait()
117
- except Exception:
118
- return "", "No output captured (possibly killed).", 0.0
119
 
120
- return result.get("stdout", ""), result.get("stderr", ""), float(result.get("elapsed", 0.0))
121
-
122
-
123
- # -----------------------------
124
  # Gradio UI
125
- # -----------------------------
126
- EXAMPLE_CODE = """
127
- import requests
128
- r = requests.get("https://httpbin.org/get")
129
- print("Status:", r.status_code)
130
- print("JSON:", r.json())
131
- """.strip()
132
-
133
-
134
- def interface_run(code, stdin_text, timeout_s, mem_limit):
135
- stdout, stderr, elapsed = run_code(code or "", stdin_text or "", timeout_s or 5.0, mem_limit or 512)
136
- status = f"Finished in {elapsed:.3f}s"
137
- return stdout, stderr, status
138
-
139
-
140
- with gr.Blocks(title="Python Code Runner (Free Sandbox)") as demo:
141
- gr.Markdown("""
142
- # 🐍 Python Code Runner (Free Sandbox)
143
- اجرای کد پایتون با نصب خودکار هر کتابخانه‌ای که import کنید. ⚠️
144
-
145
- > توجه: این نسخه ناامن است و می‌تواند ریسک امنیتی داشته باشد.
146
- """)
147
-
148
- with gr.Row():
149
- code = gr.Code(language="python", value=EXAMPLE_CODE, lines=18, label="Python code")
150
- with gr.Row():
151
- stdin_tb = gr.Textbox(lines=3, label="stdin (optional)")
152
- with gr.Row():
153
- timeout = gr.Slider(1, 30, value=5, step=1, label="Time limit (seconds)")
154
- mem_limit = gr.Slider(64, 4096, value=512, step=64, label="Memory limit (MB)")
155
- run_btn = gr.Button("Run", variant="primary")
156
 
157
- with gr.Row():
158
- stdout = gr.Textbox(lines=12, label="stdout", interactive=False)
159
- with gr.Row():
160
- stderr = gr.Textbox(lines=8, label="stderr", interactive=False)
161
- status = gr.Label(value="Idle", label="Status")
162
 
163
- run_btn.click(interface_run, inputs=[code, stdin_tb, timeout, mem_limit], outputs=[stdout, stderr, status])
 
164
 
165
- gr.Examples(
166
- examples=[
167
- ["print('Hello from Space!')"],
168
- ["import numpy as np\nprint(np.arange(10))"],
169
- ["import requests\nprint(requests.get('https://httpbin.org/get').status_code)"],
170
- ],
171
- inputs=[code],
172
- label="Quick examples"
173
- )
174
 
175
  if __name__ == "__main__":
176
  demo.launch()
 
1
+ # app.py
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import gradio as gr
3
+ import sys, io, traceback, re, subprocess, importlib, multiprocessing, resource, signal
4
 
5
+ # ----------------------
6
+ # Helper: Install missing packages safely
7
+ # ----------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  def _install_missing(packages):
9
+ """Install packages if not already installed. Fail gracefully if not found."""
10
  for pkg in packages:
11
  try:
12
  importlib.import_module(pkg)
13
  except ImportError:
14
+ try:
15
+ subprocess.check_call(
16
+ [sys.executable, "-m", "pip", "install", "--disable-pip-version-check", "-q", pkg]
17
+ )
18
+ except subprocess.CalledProcessError:
19
+ # فقط هشدار می‌ده، برنامه نمی‌ترکه
20
+ print(f"[WARN] Package '{pkg}' not found on PyPI or failed to install.", file=sys.stderr)
21
+
22
+ # ----------------------
23
+ # Worker process
24
+ # ----------------------
25
+ def _worker(code, stdin_input, conn):
26
+ sys.stdin = io.StringIO(stdin_input)
27
+ sys.stdout = io.StringIO()
28
+ sys.stderr = io.StringIO()
29
+
30
+ # محدودیت حافظه و زمان
31
+ resource.setrlimit(resource.RLIMIT_AS, (512 * 1024 * 1024, 512 * 1024 * 1024)) # 512MB
32
+ signal.alarm(10) # 10 ثانیه تایم‌اوت
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  try:
35
+ # پیدا کردن importها
36
+ imports = re.findall(r'^\s*import (\w+)|^\s*from (\w+)', code, flags=re.MULTILINE)
37
+ imports = {i[0] or i[1] for i in imports}
 
 
 
 
 
38
  if imports:
39
  _install_missing(imports)
40
 
41
+ safe_globals = {"__builtins__": __builtins__}
42
+ exec(compile(code, "<user_code>", "exec"), safe_globals, None)
43
+ out = sys.stdout.getvalue()
44
+ err = sys.stderr.getvalue()
45
+ conn.send((out, err))
46
  except Exception:
47
+ conn.send(("", traceback.format_exc()))
48
  finally:
49
+ conn.close()
50
+
51
+ # ----------------------
52
+ # Runner
53
+ # ----------------------
54
+ def run_code(code, stdin_input=""):
55
+ parent_conn, child_conn = multiprocessing.Pipe()
56
+ p = multiprocessing.Process(target=_worker, args=(code, stdin_input, child_conn))
 
 
 
 
 
 
 
57
  p.start()
58
+ p.join(12) # یک مقدار بیشتر از تایم‌اوت داخلی
 
59
  if p.is_alive():
60
  p.terminate()
61
+ return "", "Error: Timeout (execution took too long)"
62
+ return parent_conn.recv()
 
 
 
 
 
 
63
 
64
+ # ----------------------
 
 
 
65
  # Gradio UI
66
+ # ----------------------
67
+ with gr.Blocks(title="Python Runner (Auto Install)") as demo:
68
+ gr.Markdown("### 🐍 Python Sandbox with Auto-Package Install (USE WITH CAUTION)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
+ code = gr.Code(label="Python code", language="python")
71
+ stdin = gr.Textbox(label="stdin", placeholder="Optional input for `input()` calls")
72
+ run_btn = gr.Button("▶ Run")
73
+ stdout = gr.Textbox(label="stdout")
74
+ stderr = gr.Textbox(label="stderr", elem_classes="stderr")
75
 
76
+ def execute(c, s):
77
+ return run_code(c, s)
78
 
79
+ run_btn.click(execute, [code, stdin], [stdout, stderr])
 
 
 
 
 
 
 
 
80
 
81
  if __name__ == "__main__":
82
  demo.launch()