Spaces:
Running
Running
| from asyncio import create_subprocess_exec, subprocess | |
| class Terminal: | |
| """ | |
| Class for running terminal commands asynchronously. | |
| Methods: | |
| run(commands: str) | |
| commands: Terminal Commands. | |
| Returns Process id (int) | |
| terminate(pid: int) | |
| pid: Process id returned in `run` method. | |
| Returns True if terminated else False (bool) | |
| output(pid: int) | |
| pid: Process id returned in `run` method. | |
| Returns Output of process (str) | |
| error(pid: int) | |
| pid: Process id returned in `run` method. | |
| Returns Error of process (str) | |
| """ | |
| def __init__(self) -> None: | |
| self._processes = {} | |
| def _to_str(data: bytes) -> str: | |
| return data.decode("utf-8").strip() | |
| async def run(self, *args) -> int: | |
| process = await create_subprocess_exec( | |
| *args, stdout=subprocess.PIPE, stderr=subprocess.PIPE | |
| ) | |
| pid = process.pid | |
| self._processes[pid] = process | |
| return pid | |
| def terminate(self, pid: int) -> bool: | |
| try: | |
| self._processes.pop(pid) | |
| self._processes[pid].kill() | |
| return True | |
| except KeyError: | |
| return False | |
| async def output(self, pid: int) -> str: | |
| output = [] | |
| while True: | |
| out = self._to_str(await self._processes[pid].stdout.readline()) | |
| if not out: | |
| break | |
| output.append(out) | |
| return "\n".join(output) | |
| async def error(self, pid: int) -> str: | |
| error = [] | |
| while True: | |
| err = self._to_str(await self._processes[pid].stderr.readline()) | |
| if not err: | |
| break | |
| error.append(err) | |
| return "\n".join(error) | |
| def _auto_remove_processes(self) -> None: | |
| while self._processes: | |
| for proc in self._processes.keys(): | |
| if proc.returncode is not None: # process is still running | |
| try: | |
| self._processes.pop(proc) | |
| except KeyError: | |
| pass | |