ror-12 commited on
Commit
32880eb
·
verified ·
1 Parent(s): 0b5a8d9

Create executor.py

Browse files
Files changed (1) hide show
  1. executor.py +142 -0
executor.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import os
3
+ import shutil
4
+ import uuid
5
+ import time
6
+ import tempfile
7
+ from typing import List, Dict, Any, Optional
8
+
9
+ class CodeExecutor:
10
+ def __init__(self):
11
+ # Mapping languages to their extensions and execution commands
12
+ self.languages = {
13
+ "python": {"ext": "py", "cmd": "python3"},
14
+ "javascript": {"ext": "js", "cmd": "node"},
15
+ "cpp": {"ext": "cpp", "compiler": "g++", "out": "code_out"},
16
+ "c": {"ext": "c", "compiler": "gcc", "out": "code_out"},
17
+ "java": {"ext": "java", "compiler": "javac", "class_name": "Main"}
18
+ }
19
+
20
+ def _resolve_binary(self, binary: str) -> str:
21
+ """Checks if a binary exists in the system path."""
22
+ path = shutil.which(binary)
23
+ if not path:
24
+ raise FileNotFoundError(f"Compiler/Runtime missing in container: {binary}")
25
+ return path
26
+
27
+ def run(self, language: str, code: str, test_cases: List[Dict[str, str]], time_limit: float = 2.0) -> List[Dict[str, Any]]:
28
+ if language not in self.languages:
29
+ return [{"status": "Error", "message": f"Language {language} not supported"}]
30
+
31
+ lang_config = self.languages[language]
32
+ results = []
33
+
34
+ # Create a unique sandbox directory for this execution
35
+ temp_dir = tempfile.mkdtemp(prefix=f"exec_{uuid.uuid4().hex}_")
36
+
37
+ try:
38
+ # 1. Write the code to a file
39
+ file_name = f"Main.{lang_config['ext']}" if language == "java" else f"solution.{lang_config['ext']}"
40
+ file_path = os.path.join(temp_dir, file_name)
41
+
42
+ with open(file_path, "w") as f:
43
+ f.write(code)
44
+
45
+ # 2. Compile Phase (if applicable)
46
+ exec_path = file_path
47
+ if "compiler" in lang_config:
48
+ compiler_bin = self._resolve_binary(lang_config["compiler"])
49
+
50
+ if language in ["cpp", "c"]:
51
+ out_path = os.path.join(temp_dir, lang_config["out"])
52
+ compile_cmd = [compiler_bin, file_path, "-o", out_path]
53
+ exec_path = out_path
54
+ elif language == "java":
55
+ compile_cmd = [compiler_bin, file_path]
56
+ # Java exec path remains the class name, but we run from temp_dir
57
+ exec_path = "Main"
58
+
59
+ compilation = subprocess.run(
60
+ compile_cmd,
61
+ capture_output=True,
62
+ text=True,
63
+ timeout=10
64
+ )
65
+
66
+ if compilation.returncode != 0:
67
+ return [{
68
+ "status": "Compilation Error",
69
+ "stderr": compilation.stderr,
70
+ "stdout": compilation.stdout
71
+ }]
72
+
73
+ # 3. Execution Phase (Loop through test cases)
74
+ for i, tc in enumerate(test_cases):
75
+ input_data = tc.get("input", "")
76
+ expected_output = tc.get("expected", "").strip()
77
+
78
+ run_cmd = []
79
+ if language == "python":
80
+ run_cmd = [self._resolve_binary("python3"), file_path]
81
+ elif language == "javascript":
82
+ run_cmd = [self._resolve_binary("node"), file_path]
83
+ elif language == "java":
84
+ run_cmd = [self._resolve_binary("java"), "-cp", temp_dir, "Main"]
85
+ else: # C/C++
86
+ run_cmd = [exec_path]
87
+
88
+ start_time = time.perf_counter()
89
+ try:
90
+ process = subprocess.run(
91
+ run_cmd,
92
+ input=input_data,
93
+ capture_output=True,
94
+ text=True,
95
+ timeout=time_limit,
96
+ cwd=temp_dir # Run inside the sandbox
97
+ )
98
+ end_time = time.perf_counter()
99
+
100
+ actual_output = process.stdout.strip()
101
+ execution_time = round(end_time - start_time, 4)
102
+
103
+ if process.returncode != 0:
104
+ results.append({
105
+ "test_case": i,
106
+ "status": "Runtime Error",
107
+ "stderr": process.stderr,
108
+ "time": execution_time
109
+ })
110
+ elif actual_output == expected_output:
111
+ results.append({
112
+ "test_case": i,
113
+ "status": "Accepted",
114
+ "time": execution_time
115
+ })
116
+ else:
117
+ results.append({
118
+ "test_case": i,
119
+ "status": "Wrong Answer",
120
+ "expected": expected_output,
121
+ "actual": actual_output,
122
+ "time": execution_time
123
+ })
124
+
125
+ except subprocess.TimeoutExpired:
126
+ results.append({
127
+ "test_case": i,
128
+ "status": "Time Limit Exceeded",
129
+ "time": time_limit
130
+ })
131
+ except Exception as e:
132
+ results.append({
133
+ "test_case": i,
134
+ "status": "Internal Error",
135
+ "message": str(e)
136
+ })
137
+
138
+ finally:
139
+ # Cleanup sandbox
140
+ shutil.rmtree(temp_dir, ignore_errors=True)
141
+
142
+ return results