samarth upadhyay commited on
Commit
0208d9d
·
verified ·
1 Parent(s): d7b64ec

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +176 -0
app.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
10
+
11
+ app = Flask(__name__)
12
+ 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
+
163
+ ### How to use this API from your HTML/Frontend
164
+
165
+ **1. For Python (Existing)**
166
+ URL: `https://your-space-url.hf.space/api/run-python`
167
+ Body: `{"code": "print(1+1)"}`
168
+
169
+ **2. For SQL (New)**
170
+ URL: `https://your-space-url.hf.space/api/run-sql`
171
+ Body:
172
+ ```json
173
+ {
174
+ "type": "mysql",
175
+ "code": "CREATE TABLE test (id INT); INSERT INTO test VALUES (1); SELECT * FROM test;"
176
+ }