-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexecutor.py
72 lines (56 loc) · 1.93 KB
/
executor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from __future__ import annotations
import shlex
import subprocess
import typing
from functools import partial
class ExecutorClass(typing.Protocol):
def __call__(
self, command: str, *args: typing.Any, **kwargs: typing.Any
) -> typing.Any: ...
class Executor(typing.Protocol):
executor: ExecutorClass
errors_list: typing.Iterable[type[BaseException]]
@classmethod
def format(cls, command: str, args: list) -> str:
return shlex.join([command, *args])
@classmethod
def execute(
cls, command: str, *args, process_input: str | bytes | None = None
) -> dict:
return cls.executor(cls.format(command, *args), input=process_input)
class ShellExecutor(Executor):
executor = partial(
subprocess.run,
shell=True,
check=True,
encoding="UTF-8",
capture_output=True,
)
errors_list = (subprocess.CalledProcessError,)
@classmethod
def execute(
cls, command: str, args: list, process_input: str | bytes | None = None
) -> dict:
try:
result = cls.executor(cls.format(command, args), input=process_input)
return {
"result": result.stdout,
"error_info": result.stderr,
}
except cls.errors_list as error:
error_message = f"""
Code: {error.returncode}
Command: {error.cmd}
Output: {error.stdout}
Info: {error.stderr}
"""
raise ValueError(error_message) from None
class Commander(typing.Protocol):
executor: Executor
@classmethod
def run_args(
cls, command: str, args: list, process_input: str | bytes | None = None
) -> dict:
return cls.executor.execute(command, args, process_input=process_input)
class ShellCommander(Commander):
executor = ShellExecutor