Spaces:
Running
Running
| from __future__ import annotations | |
| import logging | |
| import os | |
| import signal | |
| import subprocess | |
| from typing import Dict, Any, List | |
| _logger = logging.getLogger(__name__) | |
| def run_subprocess( | |
| cmd: List[str], | |
| timeout: float, | |
| max_output: int = 65536, | |
| ) -> Dict[str, Any]: | |
| """Run a subprocess with timeout handling and output capture. | |
| Consolidates the duplicate subprocess logic from code_executor_service | |
| and csv_analysis_service. | |
| """ | |
| proc = subprocess.Popen( | |
| cmd, | |
| stdin=subprocess.DEVNULL, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| ) | |
| try: | |
| stdout_bytes, stderr_bytes = proc.communicate(timeout=timeout) | |
| timed_out = False | |
| except subprocess.TimeoutExpired: | |
| try: | |
| if os.name == "nt": | |
| proc.kill() | |
| else: | |
| os.killpg(os.getpgid(proc.pid), signal.SIGKILL) | |
| except Exception: | |
| proc.kill() | |
| stdout_bytes, stderr_bytes = proc.communicate() | |
| timed_out = True | |
| return { | |
| "stdout": (stdout_bytes.decode("utf-8", errors="replace")[:max_output] if stdout_bytes else ""), | |
| "stderr": (stderr_bytes.decode("utf-8", errors="replace")[:max_output] if stderr_bytes else ""), | |
| "exit_code": proc.returncode, | |
| "timed_out": timed_out, | |
| } | |