samarth upadhyay commited on
Commit
d165403
·
verified ·
1 Parent(s): 342df16

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -133
app.py CHANGED
@@ -1,9 +1,6 @@
1
  import os
2
  import subprocess
3
  import tempfile
4
- import sqlite3
5
- import psycopg2
6
- import pymysql
7
  import sys
8
  from flask import Flask, request, jsonify
9
  from flask_cors import CORS
@@ -13,163 +10,96 @@ CORS(app)
13
 
14
  @app.route('/')
15
  def home():
16
- return jsonify({
17
- "status": "ok",
18
- "message": "Playground Backend Running. Use /api/run-python or /api/run-sql"
19
- })
20
 
21
- # --- PYTHON RUNNER ---
22
- @app.route('/api/run-python', methods=['POST'])
23
- def run_python():
24
- code = request.json.get('code', '')
25
- user_input = request.json.get('input', '')
26
- if not code:
27
- return jsonify({'error': 'No code provided.'}), 400
28
-
29
- temp_file_path = None
30
  try:
31
- with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode='w', encoding='utf-8') as temp_file:
32
- temp_file.write(code)
33
- temp_file_path = temp_file.name
34
-
35
  run_process = subprocess.run(
36
- [sys.executable, temp_file_path], # Use current python executable
37
- input=user_input,
38
  capture_output=True,
39
  text=True,
40
- timeout=15
41
  )
42
-
43
- # Return stdout if successful, or stderr if failed
44
- if run_process.returncode != 0:
45
- return jsonify({'output': run_process.stderr or run_process.stdout})
46
- else:
47
- return jsonify({'output': run_process.stdout})
48
-
49
  except subprocess.TimeoutExpired:
50
- return jsonify({'output': 'Error: Code execution timed out (15s limit).'})
51
  except Exception as e:
52
- return jsonify({'output': f"Error: {str(e)}"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  finally:
54
- if temp_file_path and os.path.exists(temp_file_path):
55
- os.remove(temp_file_path)
56
 
57
- # --- SQL RUNNER ---
58
  @app.route('/api/run-sql', methods=['POST'])
59
  def run_sql():
60
  data = request.json
61
  sql_code = data.get('code', '')
62
- # Default to sqlite if not specified
63
  db_type = data.get('type', 'sqlite').lower()
64
 
65
- if not sql_code:
66
- return jsonify({'error': 'No SQL code provided.'}), 400
67
-
68
- output_log = ""
69
 
 
 
70
  try:
71
- # 1. SQLITE (In-Memory)
 
 
 
 
 
72
  if db_type == 'sqlite':
73
- # Create a fresh in-memory DB every time
74
- con = sqlite3.connect(':memory:')
75
- cur = con.cursor()
76
- try:
77
- # executescript allows multiple statements (CREATE + INSERT + SELECT)
78
- cur.executescript(sql_code)
79
- output_log = "Executed successfully.\n"
80
-
81
- # Simple heuristic: If user didn't print anything, try to verify tables
82
- # But sqlite3 executescript doesn't return rows.
83
- # Use a specific fetch loop if you want to support SELECTs explicitly
84
- # or tell users to use PRINT in python.
85
- # For SQL playground, we usually just run it.
86
- # To show data, we can iterate cursor if the last statement was SELECT.
87
- # (Complex to detect in executescript, so we just return success message)
88
- output_log += "(Note: SQLite script ran. If you need results, ensure your frontend handles 'select' logic or splits queries)"
89
- except Exception as e:
90
- output_log = f"SQLite Error: {e}"
91
- finally:
92
- con.close()
93
 
94
- # 2. POSTGRESQL
95
  elif db_type in ['postgres', 'postgresql']:
96
- # Connect using the 'playground' user we created in start.sh
97
- # No password needed because of 'trust' in pg_hba.conf
98
- con = psycopg2.connect(
99
- host="localhost",
100
- user="playground",
101
- database="playground"
102
- )
103
- con.autocommit = True
104
- cur = con.cursor()
105
- try:
106
- # Psycopg2 execute cannot run multiple statements easily separated by ;
107
- # unless we use simple execute.
108
- cur.execute(sql_code)
109
-
110
- if cur.description:
111
- rows = cur.fetchall()
112
- colnames = [desc[0] for desc in cur.description]
113
- output_log = f"Columns: {colnames}\n"
114
- for row in rows:
115
- output_log += f"{row}\n"
116
- else:
117
- output_log = f"Command executed. Rows affected: {cur.rowcount}"
118
- except Exception as e:
119
- output_log = f"PostgreSQL Error: {e}"
120
- finally:
121
- con.close()
122
 
123
- # 3. MYSQL / MARIADB
124
  elif db_type == 'mysql':
125
- # Connect using the 'playground' user from start.sh
126
- con = pymysql.connect(
127
- host="localhost",
128
- user="playground",
129
- database="playground",
130
- cursorclass=pymysql.cursors.DictCursor,
131
- client_flag=pymysql.constants.CLIENT.MULTI_STATEMENTS
132
- )
133
- try:
134
- with con.cursor() as cur:
135
- cur.execute(sql_code)
136
- # Fetch results from all statements
137
- while True:
138
- if cur.description:
139
- rows = cur.fetchall()
140
- output_log += f"--- Result ---\n{rows}\n"
141
- else:
142
- output_log += f"Affected rows: {cur.rowcount}\n"
143
- if not cur.nextset():
144
- break
145
- except Exception as e:
146
- output_log = f"MySQL Error: {e}"
147
- finally:
148
- con.close()
149
 
150
  else:
151
- return jsonify({'output': 'Error: Unsupported database type'}), 400
152
 
153
- return jsonify({'output': output_log})
154
 
155
- except Exception as e:
156
- return jsonify({'output': f"System Error: {str(e)}"})
 
157
 
158
  if __name__ == '__main__':
159
  # Hugging Face expects port 7860
160
- app.run(host="0.0.0.0", port=7860)
161
-
162
- ### How to use this API from your HTML/Frontend
163
-
164
- **1. For Python (Existing)**
165
- URL: `https://your-space-url.hf.space/api/run-python`
166
- Body: `{"code": "print(1+1)"}`
167
-
168
- **2. For SQL (New)**
169
- URL: `https://your-space-url.hf.space/api/run-sql`
170
- Body:
171
- ```json
172
- {
173
- "type": "mysql",
174
- "code": "CREATE TABLE test (id INT); INSERT INTO test VALUES (1); SELECT * FROM test;"
175
- }
 
1
  import os
2
  import subprocess
3
  import tempfile
 
 
 
4
  import sys
5
  from flask import Flask, request, jsonify
6
  from flask_cors import CORS
 
10
 
11
  @app.route('/')
12
  def home():
13
+ return jsonify({"status": "ok", "message": "API Running. POST to /api/run-python or /api/run-sql"})
 
 
 
14
 
15
+ def run_command(command, input_text=None, timeout=15):
16
+ """Helper to run shell commands safely"""
 
 
 
 
 
 
 
17
  try:
 
 
 
 
18
  run_process = subprocess.run(
19
+ command,
20
+ input=input_text,
21
  capture_output=True,
22
  text=True,
23
+ timeout=timeout
24
  )
25
+ # Return stdout if success, stderr if fail (or both)
26
+ output = run_process.stdout
27
+ if run_process.stderr:
28
+ # Append stderr to output so user sees errors
29
+ output += "\n--- Error Log ---\n" + run_process.stderr
30
+ return output
 
31
  except subprocess.TimeoutExpired:
32
+ return "Error: Execution timed out (15s limit)."
33
  except Exception as e:
34
+ return f"System Error: {str(e)}"
35
+
36
+ @app.route('/api/run-python', methods=['POST'])
37
+ def run_python():
38
+ code = request.json.get('code', '')
39
+ user_input = request.json.get('input', '') # Optional stdin input
40
+
41
+ if not code: return jsonify({'output': 'No code provided'}), 400
42
+
43
+ # Write code to temp file
44
+ temp_path = None
45
+ try:
46
+ with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode='w', encoding='utf-8') as f:
47
+ f.write(code)
48
+ temp_path = f.name
49
+
50
+ # Run python using the current environment's python executable
51
+ output = run_command([sys.executable, temp_path], input_text=user_input)
52
+ return jsonify({'output': output})
53
+
54
  finally:
55
+ if temp_path and os.path.exists(temp_path):
56
+ os.remove(temp_path)
57
 
 
58
  @app.route('/api/run-sql', methods=['POST'])
59
  def run_sql():
60
  data = request.json
61
  sql_code = data.get('code', '')
 
62
  db_type = data.get('type', 'sqlite').lower()
63
 
64
+ if not sql_code: return jsonify({'output': 'No SQL code provided'}), 400
 
 
 
65
 
66
+ # Write SQL to temp file (safer for some CLI tools)
67
+ temp_sql_path = None
68
  try:
69
+ with tempfile.NamedTemporaryFile(suffix=".sql", delete=False, mode='w', encoding='utf-8') as f:
70
+ f.write(sql_code)
71
+ temp_sql_path = f.name
72
+
73
+ output = ""
74
+
75
  if db_type == 'sqlite':
76
+ # Run sqlite3 against an in-memory DB
77
+ # We pass the SQL content via stdin
78
+ cmd = ["sqlite3", ":memory:"]
79
+ output = run_command(cmd, input_text=sql_code)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
 
81
  elif db_type in ['postgres', 'postgresql']:
82
+ # Run psql using the 'playground' user defined in start.sh
83
+ # -f runs the file provided
84
+ cmd = ["psql", "-h", "localhost", "-U", "playground", "-d", "playground", "-f", temp_sql_path]
85
+ output = run_command(cmd)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
 
87
  elif db_type == 'mysql':
88
+ # Run mysql using the 'playground' user defined in start.sh
89
+ # -t forces ASCII table output even in non-interactive mode
90
+ cmd = ["mysql", "-h", "localhost", "-u", "playground", "playground", "-t"]
91
+ # Pass SQL via stdin
92
+ output = run_command(cmd, input_text=sql_code)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
  else:
95
+ return jsonify({'output': 'Unsupported database type. Use sqlite, postgres, or mysql.'}), 400
96
 
97
+ return jsonify({'output': output})
98
 
99
+ finally:
100
+ if temp_sql_path and os.path.exists(temp_sql_path):
101
+ os.remove(temp_sql_path)
102
 
103
  if __name__ == '__main__':
104
  # Hugging Face expects port 7860
105
+ app.run(host="0.0.0.0", port=7860)