| 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 = {} |
|
|
| @staticmethod |
| 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) |
|
|
| @property |
| def _auto_remove_processes(self) -> None: |
| while self._processes: |
| for proc in self._processes.keys(): |
| if proc.returncode is not None: |
| try: |
| self._processes.pop(proc) |
| except KeyError: |
| pass |
|
|