Skip to content

Commit dc48cd9

Browse files
authored
Make CommandResult a dataclass (#722)
1 parent 76170a4 commit dc48cd9

File tree

4 files changed

+32
-50
lines changed

4 files changed

+32
-50
lines changed

testinfra/backend/ansible.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,9 @@ def run(self, command: str, *args: str, **kwargs: Any) -> base.CommandResult:
5858
out = self.run_ansible("shell", module_args=command, check=False)
5959
return self.result(
6060
out["rc"],
61-
command,
62-
stdout_bytes=None,
63-
stderr_bytes=None,
64-
stdout=out["stdout"],
65-
stderr=out["stderr"],
61+
self.encode(command),
62+
out["stdout"],
63+
out["stderr"],
6664
)
6765

6866
def run_ansible(

testinfra/backend/base.py

+27-41
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import shlex
1818
import subprocess
1919
import urllib.parse
20-
from typing import TYPE_CHECKING, Any, Optional
20+
from typing import TYPE_CHECKING, Any, Optional, Union
2121

2222
if TYPE_CHECKING:
2323
import testinfra.host
@@ -33,6 +33,7 @@ class HostSpec:
3333
password: Optional[str]
3434

3535

36+
@dataclasses.dataclass
3637
class CommandResult:
3738
"""Object that encapsulates all returned details of the command execution.
3839
@@ -51,24 +52,11 @@ class CommandResult:
5152
False
5253
"""
5354

54-
def __init__(
55-
self,
56-
backend: "BaseBackend",
57-
exit_status: int,
58-
command: bytes,
59-
stdout_bytes: bytes,
60-
stderr_bytes: bytes,
61-
stdout: Optional[str] = None,
62-
stderr: Optional[str] = None,
63-
):
64-
self.exit_status = exit_status
65-
self._stdout_bytes = stdout_bytes
66-
self._stderr_bytes = stderr_bytes
67-
self._stdout = stdout
68-
self._stderr = stderr
69-
self.command = command
70-
self._backend = backend
71-
super().__init__()
55+
backend: "BaseBackend"
56+
exit_status: int
57+
command: bytes
58+
_stdout: Union[str, bytes]
59+
_stderr: Union[str, bytes]
7260

7361
@property
7462
def succeeded(self) -> bool:
@@ -104,8 +92,8 @@ def stdout(self) -> str:
10492
>>> host.run("mkdir -v new_directory").stdout
10593
mkdir: created directory 'new_directory'
10694
"""
107-
if self._stdout is None:
108-
self._stdout = self._backend.decode(self._stdout_bytes)
95+
if isinstance(self._stdout, bytes):
96+
return self.backend.decode(self._stdout)
10997
return self._stdout
11098

11199
@property
@@ -115,8 +103,8 @@ def stderr(self) -> str:
115103
>>> host.run("mkdir new_directory").stderr
116104
mkdir: cannot create directory 'new_directory': File exists
117105
"""
118-
if self._stderr is None:
119-
self._stderr = self._backend.decode(self._stderr_bytes)
106+
if isinstance(self._stderr, bytes):
107+
return self.backend.decode(self._stderr)
120108
return self._stderr
121109

122110
@property
@@ -126,9 +114,9 @@ def stdout_bytes(self) -> bytes:
126114
>>> host.run("mkdir -v new_directory").stdout_bytes
127115
b"mkdir: created directory 'new_directory'"
128116
"""
129-
if self._stdout_bytes is None:
130-
self._stdout_bytes = self._backend.encode(self._stdout)
131-
return self._stdout_bytes
117+
if isinstance(self._stdout, str):
118+
return self.backend.encode(self._stdout)
119+
return self._stdout
132120

133121
@property
134122
def stderr_bytes(self) -> bytes:
@@ -137,19 +125,9 @@ def stderr_bytes(self) -> bytes:
137125
>>> host.run("mkdir new_directory").stderr_bytes
138126
b"mkdir: cannot create directory 'new_directory': File exists"
139127
"""
140-
if self._stderr_bytes is None:
141-
self._stderr_bytes = self._backend.encode(self._stderr)
142-
return self._stderr_bytes
143-
144-
def __repr__(self) -> str:
145-
return (
146-
"CommandResult(command={!r}, exit_status={}, stdout={!r}, " "stderr={!r})"
147-
).format(
148-
self.command,
149-
self.exit_status,
150-
self._stdout_bytes or self._stdout,
151-
self._stderr_bytes or self._stderr,
152-
)
128+
if isinstance(self._stderr, str):
129+
return self.backend.encode(self._stderr)
130+
return self._stderr
153131

154132

155133
class BaseBackend(metaclass=abc.ABCMeta):
@@ -337,7 +315,15 @@ def encode(self, data: str) -> bytes:
337315
except UnicodeEncodeError:
338316
return data.encode(self.encoding)
339317

340-
def result(self, *args: Any, **kwargs: Any) -> CommandResult:
341-
result = CommandResult(self, *args, **kwargs)
318+
def result(
319+
self, rc: int, cmd: bytes, stdout: Union[str, bytes], stderr: Union[str, bytes]
320+
) -> CommandResult:
321+
result = CommandResult(
322+
backend=self,
323+
exit_status=rc,
324+
command=cmd,
325+
_stdout=stdout,
326+
_stderr=stderr,
327+
)
342328
logger.debug("RUN %s", result)
343329
return result

testinfra/backend/salt.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ def run(self, command: str, *args: str, **kwargs: Any) -> base.CommandResult:
4040
out = self.run_salt("cmd.run_all", [command])
4141
return self.result(
4242
out["retcode"],
43-
command,
44-
out["stdout"].encode("utf8"),
45-
out["stderr"].encode("utf8"),
43+
self.encode(command),
4644
stdout=out["stdout"],
4745
stderr=out["stderr"],
4846
)

testinfra/backend/winrm.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def run_winrm(self, command: str, *args: str) -> base.CommandResult:
8888
stdout, stderr, rc = p.get_command_output(shell_id, command_id)
8989
p.cleanup_command(shell_id, command_id)
9090
p.close_shell(shell_id)
91-
return self.result(rc, command, stdout, stderr)
91+
return self.result(rc, self.encode(command), stdout, stderr)
9292

9393
@staticmethod
9494
def quote(command: str, *args: str) -> str:

0 commit comments

Comments
 (0)