import subprocess from pathlib import Path # Maximum time (seconds) a subprocess is allowed to run before being killed. RUN_TIMEOUT = 30 class ExecutionEngine: """Runs files from the editor in a subprocess and returns the output. Currently supports Python (.py) and LaTeX (.tex) files. Returns a dict with keys: stdout, stderr, rc (return code). """ def __init__(self): pass def run_code(self, active_file: Path) -> dict: """Execute the given file and return its output. Args: active_file: Absolute path to the file that should be run. Returns: {"stdout": str, "stderr": str, "rc": int} rc == 0 means success, anything else is an error. """ suffix = active_file.suffix current_dir = active_file.parent.resolve() # Build the shell command depending on file type if suffix == ".py": cmd = ["py", active_file.name] elif suffix == ".tex": # pdflatex in non-interactive mode so it never waits for input cmd = [ "pdflatex", "-interaction=nonstopmode", f"-output-directory={current_dir}", active_file.name, ] else: return {"stdout": "", "stderr": f"Unsupported file type: {suffix}", "rc": 1} try: proc = subprocess.run( cmd, cwd=current_dir, # run inside the file's own directory capture_output=True, text=True, timeout=RUN_TIMEOUT, ) return {"stdout": proc.stdout, "stderr": proc.stderr, "rc": proc.returncode} except subprocess.TimeoutExpired: return {"stdout": "", "stderr": f"Timed out after {RUN_TIMEOUT}s", "rc": -1} except FileNotFoundError as e: # Raised when the interpreter/compiler binary is not found on PATH return {"stdout": "", "stderr": str(e), "rc": -1} except Exception as e: return {"stdout": "", "stderr": str(e), "rc": -1}