import subprocess, tempfile, shutil, traceback, importlib.util import concurrent.futures import os class CodeExecutor: def __init__(self): self.temp_dir = tempfile.TemporaryDirectory() self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) def _install_packages(self, packages): for package in packages: package = package.strip() if not package: continue try: spec = importlib.util.find_spec(package) if spec is None: subprocess.check_call(["pip", "install", package], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=15) except subprocess.CalledProcessError as e: raise Exception(f"❌ Error installing package {package}: {e}") except subprocess.TimeoutExpired: raise Exception(f"⏰ Timed out installing package {package}") def _execute_code(self, code, inputs): temp_file = f"{self.temp_dir.name}/user_code.py" output_file = f"{self.temp_dir.name}/stdout.txt" error_file = f"{self.temp_dir.name}/stderr.txt" with open(temp_file, "w") as f: f.write(code) with open(output_file, "w") as out, open(error_file, "w") as err: try: process = subprocess.Popen( ["python", temp_file], stdin=subprocess.PIPE, stdout=out, stderr=err, text=True ) if inputs: for line in inputs: process.stdin.write(line + "\n") process.stdin.close() process.wait(timeout=15) except subprocess.TimeoutExpired: process.kill() err.write("⏰ Execution timed out.\n") except Exception: err.write(traceback.format_exc()) with open(output_file, "r") as out, open(error_file, "r") as err: output_text = out.read().strip() error_text = err.read().strip() if error_text: return f"⚠️ Error:\n{error_text}" return f"✅ Output:\n{output_text}" def execute(self, code, inputs, packages): if packages: self._install_packages(packages.split(",")) future = self.executor.submit(self._execute_code, code, inputs) try: return future.result(timeout=20) except concurrent.futures.TimeoutError: return "⏳ Code execution exceeded time limit." except Exception as e: return f"❌ Execution Error: {e}" def __del__(self): self.executor.shutdown(wait=False) shutil.rmtree(self.temp_dir.name)