File size: 5,580 Bytes
605b91b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import asyncio
import websockets
import json

# Replace with your actual Space URL
# For Hugging Face Spaces, use wss://<your-space-id>.hf.space/ws
WS_URL = "wss://Srevarshan1502-collaborative-python-executor.hf.space/ws"

async def run_python_code(code_to_execute: str):
    try:
        async with websockets.connect(WS_URL) as websocket:
            print("Connected to WebSocket.")

            # Send the Python code
            await websocket.send(json.dumps({"type": "code", "content": code_to_execute}))
            print(f"Sent code:\n---\n{code_to_execute}\n---")

            full_output = ""
            execution_complete = False

            while not execution_complete:
                try:
                    # Keep waiting for messages until execution_complete
                    # Increased timeout to 60 seconds as per your last script
                    message = await asyncio.wait_for(websocket.recv(), timeout=60)
                    data = json.loads(message)

                    if data["type"] == "output":
                        full_output += data["content"]
                        print(f"Received output chunk: {data['content'].strip()}")
                    elif data["type"] == "input_request":
                        print("\n--- Input Requested ---")
                        user_input = input("Please enter input for the script: ")
                        # IMPORTANT: Add newline character for the server's readline() to process it as a complete line
                        await websocket.send(json.dumps({"type": "input", "content": user_input + "\n"}))
                        print(f"Sent input: {user_input}")
                    elif data["type"] == "execution_complete":
                        print("\n--- Execution Complete ---")
                        # The 'result' field from the server's execution_complete message
                        server_result = data['result']
                        print(f"Result details from server: {server_result}")

                        # Consolidate output from the server_result as well
                        if server_result.get('output'):
                            full_output += server_result['output']
                        if server_result.get('error'):
                            # Prepend "Error:" if it's the first error message
                            if "Error from server:" not in full_output:
                                full_output += "\nError from server:\n"
                            full_output += server_result['error']
                            
                        execution_complete = True
                    elif data["type"] == "pong":
                        # print("Received pong.") # Optional: uncomment to see pongs
                        pass
                    else:
                        print(f"Received unknown message type: {data['type']} - {data.get('content')}")

                except asyncio.TimeoutError:
                    print("Timeout: No message received from server for 60 seconds. Disconnecting.")
                    break
                except websockets.exceptions.ConnectionClosedOK:
                    print("Connection closed by server (OK).")
                    # If it closes OK before execution_complete, it's an issue
                    if not execution_complete:
                        print("WARNING: Connection closed OK before execution_complete message was received!")
                    break
                except websockets.exceptions.ConnectionClosedError as e:
                    print(f"Connection closed with error: {e}")
                    break
                except json.JSONDecodeError:
                    print(f"Received invalid JSON: {message}")
                    break
                except Exception as e:
                    print(f"An unexpected error occurred during message reception: {e}")
                    break

            print("\n--- Final Consolidated Output ---")
            print(full_output)
            return full_output

    except websockets.exceptions.InvalidURI as e:
        print(f"Invalid WebSocket URI: {e}")
    except ConnectionRefusedError:
        print("Connection refused. Is the server running and accessible?")
    except Exception as e:
        print(f"Could not connect to WebSocket: {e}")
    return None

if __name__ == "__main__":
    # Test 1: Simple print statement (Matches the current app.py test 1)
    print("\n=== Running Test 1: Simple Print ===")
    asyncio.run(run_python_code(code_to_execute = "print('Hello, Space!')"))

    # Test 2: Code with interactive input (corrected syntax)
    print("\n=== Running Test 2: Interactive Input ===")
    interactive_code = """
name = input("Enter your name: ")
age = int(input("How old are you? "))
print(f"Hello, {name}! You are {age} years old.")
"""
    # For app.py's Test 2 (where exec is not yet active)
    # asyncio.run(run_python_code(code_to_execute="DUMMY_CODE_FOR_TESTING_SYS_REDIRECTION"))

    # Once app.py has Test 3 (with exec) uncomment this:
    asyncio.run(run_python_code(interactive_code))

    # Test 3: Code with error (uncomment when full exec is working)
    # print("\n=== Running Test 3: Code with Error ===")
    # asyncio.run(run_python_code("print(1/0)"))

    # Test 4: Long-running code (will hit timeout if not finished, uncomment when full exec is working)
    # print("\n=== Running Test 4: Long Running Code ===")
    # asyncio.run(run_python_code("import time\nfor i in range(5):\n    print(f'Counting: {i}')\n    time.sleep(1)"))