Update app.py
Browse files
app.py
CHANGED
|
@@ -60,6 +60,7 @@ class WebSocketInputOutput:
|
|
| 60 |
"""Reads a line from stdin, waiting for input from WebSocket."""
|
| 61 |
try:
|
| 62 |
print("DEBUG: Sending input_request to client.")
|
|
|
|
| 63 |
await self.websocket.send_text(json.dumps({"type": "input_request"}))
|
| 64 |
line = await self.input_queue.get() # Wait for input from client
|
| 65 |
print(f"DEBUG: Received input from queue: {line.strip()[:50]}...")
|
|
@@ -391,12 +392,12 @@ class SecurePythonExecutor:
|
|
| 391 |
|
| 392 |
# --- START TEST 1 MODIFICATIONS ---
|
| 393 |
# DO NOT redirect sys.stdin/stdout/stderr here yet
|
| 394 |
-
print(f"DEBUG: Executor thread '{threading.current_thread().name}' started. (No IO redirected yet)")
|
| 395 |
result['success'] = True
|
| 396 |
# Do not call exec yet. Just write directly to output_buffer for testing.
|
| 397 |
-
websocket_io.output_buffer.write("DEBUG: Test message from executor thread (no exec).\n")
|
| 398 |
# Do not call asyncio.run(websocket_io.write) here. The main loop will check buffer.
|
| 399 |
-
print("DEBUG: _execute_in_thread finished with direct buffer write.")
|
| 400 |
# --- END TEST 1 MODIFICATIONS ---
|
| 401 |
|
| 402 |
# Use the event loop's default ThreadPoolExecutor to run the synchronous code
|
|
@@ -438,7 +439,8 @@ class SecurePythonExecutor:
|
|
| 438 |
# Send a final message to the client indicating execution is complete
|
| 439 |
try:
|
| 440 |
print(f"DEBUG: Attempting to send execution_complete message (success={result['success']}).")
|
| 441 |
-
|
|
|
|
| 442 |
print("DEBUG: execution_complete message sent.")
|
| 443 |
except WebSocketDisconnect:
|
| 444 |
print("DEBUG: WebSocketDisconnect when sending execution_complete.")
|
|
@@ -484,17 +486,18 @@ async def websocket_endpoint(websocket: WebSocket):
|
|
| 484 |
|
| 485 |
if data["type"] == "code":
|
| 486 |
code = data["content"]
|
| 487 |
-
print(f"Received code from {websocket_io.websocket.client}: {code[:50]}...")
|
| 488 |
# Execute code asynchronously in the background
|
| 489 |
asyncio.create_task(executor.execute_code(code, websocket_io))
|
| 490 |
elif data["type"] == "input":
|
| 491 |
user_input = data["content"]
|
| 492 |
-
print(f"Received input from {websocket_io.websocket.client}: {user_input.strip()[:50]}...")
|
| 493 |
await websocket_io.input_queue.put(user_input + "\n") # Add newline for readline
|
| 494 |
elif data["type"] == "ping":
|
| 495 |
# Respond to pings to keep connection alive
|
| 496 |
-
|
| 497 |
-
|
|
|
|
| 498 |
else:
|
| 499 |
await websocket_io.write(f"Unknown message type: {data['type']}\n")
|
| 500 |
|
|
@@ -512,4 +515,29 @@ async def websocket_endpoint(websocket: WebSocket):
|
|
| 512 |
websocket_io.input_queue.get_nowait()
|
| 513 |
except asyncio.QueueEmpty:
|
| 514 |
pass
|
| 515 |
-
print(f"WebSocket connection closed for {websocket_io.websocket.client}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
"""Reads a line from stdin, waiting for input from WebSocket."""
|
| 61 |
try:
|
| 62 |
print("DEBUG: Sending input_request to client.")
|
| 63 |
+
# CORRECTED: Access send_text via self.websocket
|
| 64 |
await self.websocket.send_text(json.dumps({"type": "input_request"}))
|
| 65 |
line = await self.input_queue.get() # Wait for input from client
|
| 66 |
print(f"DEBUG: Received input from queue: {line.strip()[:50]}...")
|
|
|
|
| 392 |
|
| 393 |
# --- START TEST 1 MODIFICATIONS ---
|
| 394 |
# DO NOT redirect sys.stdin/stdout/stderr here yet
|
| 395 |
+
print(f"DEBUG: Executor thread '{threading.current_thread().name}' started. (No IO redirected yet)")
|
| 396 |
result['success'] = True
|
| 397 |
# Do not call exec yet. Just write directly to output_buffer for testing.
|
| 398 |
+
websocket_io.output_buffer.write("DEBUG: Test message from executor thread (no exec).\n")
|
| 399 |
# Do not call asyncio.run(websocket_io.write) here. The main loop will check buffer.
|
| 400 |
+
print("DEBUG: _execute_in_thread finished with direct buffer write.")
|
| 401 |
# --- END TEST 1 MODIFICATIONS ---
|
| 402 |
|
| 403 |
# Use the event loop's default ThreadPoolExecutor to run the synchronous code
|
|
|
|
| 439 |
# Send a final message to the client indicating execution is complete
|
| 440 |
try:
|
| 441 |
print(f"DEBUG: Attempting to send execution_complete message (success={result['success']}).")
|
| 442 |
+
# CORRECTED: Access send_text via websocket_io.websocket
|
| 443 |
+
await websocket_io.websocket.send_text(json.dumps({"type": "execution_complete", "result": result}))
|
| 444 |
print("DEBUG: execution_complete message sent.")
|
| 445 |
except WebSocketDisconnect:
|
| 446 |
print("DEBUG: WebSocketDisconnect when sending execution_complete.")
|
|
|
|
| 486 |
|
| 487 |
if data["type"] == "code":
|
| 488 |
code = data["content"]
|
| 489 |
+
print(f"Received code from {websocket_io.websocket.client}: {code[:50]}...")
|
| 490 |
# Execute code asynchronously in the background
|
| 491 |
asyncio.create_task(executor.execute_code(code, websocket_io))
|
| 492 |
elif data["type"] == "input":
|
| 493 |
user_input = data["content"]
|
| 494 |
+
print(f"Received input from {websocket_io.websocket.client}: {user_input.strip()[:50]}...")
|
| 495 |
await websocket_io.input_queue.put(user_input + "\n") # Add newline for readline
|
| 496 |
elif data["type"] == "ping":
|
| 497 |
# Respond to pings to keep connection alive
|
| 498 |
+
# CORRECTED: Access send_text via websocket_io.websocket
|
| 499 |
+
await websocket_io.websocket.send_text(json.dumps({"type": "pong"}))
|
| 500 |
+
print(f"DEBUG: Sent pong to {websocket_io.websocket.client}")
|
| 501 |
else:
|
| 502 |
await websocket_io.write(f"Unknown message type: {data['type']}\n")
|
| 503 |
|
|
|
|
| 515 |
websocket_io.input_queue.get_nowait()
|
| 516 |
except asyncio.QueueEmpty:
|
| 517 |
pass
|
| 518 |
+
print(f"WebSocket connection closed for {websocket_io.websocket.client}")
|
| 519 |
+
|
| 520 |
+
# This block is for local development using `uvicorn`
|
| 521 |
+
# Hugging Face Spaces will use `uvicorn` directly via the Dockerfile CMD
|
| 522 |
+
if __name__ == "__main__":
|
| 523 |
+
import uvicorn
|
| 524 |
+
print("Starting Interactive Python Code Executor API (FastAPI)...")
|
| 525 |
+
print(f"Python version: {sys.version}")
|
| 526 |
+
print(f"Working directory: {os.getcwd()}")
|
| 527 |
+
|
| 528 |
+
server_name = os.getenv('FASTAPI_SERVER_NAME', '0.0.0.0')
|
| 529 |
+
server_port = int(os.getenv('FASTAPI_SERVER_PORT', 7860))
|
| 530 |
+
|
| 531 |
+
print(f"Starting server on {server_name}:{server_port}")
|
| 532 |
+
|
| 533 |
+
try:
|
| 534 |
+
uvicorn.run(
|
| 535 |
+
"app:app", # app:app means the `app` object in `app.py`
|
| 536 |
+
host=server_name,
|
| 537 |
+
port=server_port,
|
| 538 |
+
reload=False, # Set to True for local dev to auto-reload on code changes
|
| 539 |
+
log_level="info"
|
| 540 |
+
)
|
| 541 |
+
except Exception as e:
|
| 542 |
+
print(f"Failed to start server: {e}")
|
| 543 |
+
sys.exit(1)
|