Skip to content

Commit eb1c3d1

Browse files
authored
Extend ExecHelperTimeoutError Fix #43 (#44)
* Extend ExecHelperTimeoutError Fix #43 * Re-subclass `ExecCalledProcessError` * Provide timeout and result * Add properties to access cmd, stdout_str and stderr_str
1 parent 814d435 commit eb1c3d1

File tree

7 files changed

+122
-20
lines changed

7 files changed

+122
-20
lines changed

doc/source/exceptions.rst

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,45 @@ API: exceptions
1414
1515
Deserialize impossible.
1616

17-
.. py:exception:: ExecHelperTimeoutError(ExecHelperError)
17+
.. py:exception:: ExecCalledProcessError(ExecHelperError)
18+
19+
Base class for process call errors.
20+
21+
.. py:exception:: ExecHelperTimeoutError(ExecCalledProcessError)
1822
1923
Execution timeout.
2024

21-
.. py:exception:: ExecCalledProcessError(ExecHelperError)
25+
.. versionchanged:: 1.3.0 provide full result and timeout inside.
26+
.. versionchanged:: 1.3.0 subclass ExecCalledProcessError
2227

23-
Base class for process call errors.
28+
.. py:method:: __init__(self, result, timeout)
29+
30+
Exception for error on process calls.
31+
32+
:param result: execution result
33+
:type result: exec_result.ExecResult
34+
:param timeout: timeout for command
35+
:type timeout: typing.Union[int, float]
36+
37+
.. py:attribute:: timeout
38+
39+
``int``
40+
41+
.. py:attribute:: result
42+
43+
Execution result
44+
45+
:rtype: ExecResult
46+
47+
.. py:attribute:: stdout
48+
49+
``typing.Text``
50+
stdout string or brief string
51+
52+
.. py:attribute:: stderr
53+
54+
``typing.Text``
55+
stdout string or brief string
2456

2557
.. py:exception:: CalledProcessError(ExecCalledProcessError)
2658
@@ -60,12 +92,12 @@ API: exceptions
6092

6193
.. py:attribute:: stdout
6294
63-
``typing.Any``
95+
``typing.Text``
6496
stdout string or brief string
6597

6698
.. py:attribute:: stderr
6799
68-
``typing.Any``
100+
``typing.Text``
69101
stdout string or brief string
70102

71103
.. py:exception:: ParallelCallExceptions(ExecCalledProcessError)

exec_helpers/_ssh_client_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ def poll_pipes(stop, ): # type: (threading.Event) -> None
735735
timeout=timeout
736736
)
737737
self.logger.debug(wait_err_msg)
738-
raise exceptions.ExecHelperTimeoutError(wait_err_msg)
738+
raise exceptions.ExecHelperTimeoutError(result=result, timeout=timeout)
739739

740740
def execute_through_host(
741741
self,

exec_helpers/exceptions.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import typing # noqa # pylint: disable=unused-import
2222

2323
from exec_helpers import proc_enums
24+
from exec_helpers import _log_templates
2425

2526
__all__ = (
2627
'ExecHelperError',
@@ -44,16 +45,58 @@ class DeserializeValueError(ExecHelperError, ValueError):
4445
__slots__ = ()
4546

4647

47-
class ExecHelperTimeoutError(ExecHelperError):
48-
"""Execution timeout."""
48+
class ExecCalledProcessError(ExecHelperError):
49+
"""Base class for process call errors."""
4950

5051
__slots__ = ()
5152

5253

53-
class ExecCalledProcessError(ExecHelperError):
54-
"""Base class for process call errors."""
54+
class ExecHelperTimeoutError(ExecCalledProcessError):
55+
"""Execution timeout.
5556
56-
__slots__ = ()
57+
.. versionchanged:: 1.3.0 provide full result and timeout inside.
58+
.. versionchanged:: 1.3.0 subclass ExecCalledProcessError
59+
"""
60+
61+
__slots__ = (
62+
'result',
63+
'timeout',
64+
)
65+
66+
def __init__(
67+
self,
68+
result, # type: exec_result.ExecResult
69+
timeout, # type: typing.Union[int, float]
70+
): # type: (...) -> None
71+
"""Exception for error on process calls.
72+
73+
:param result: execution result
74+
:type result: exec_result.ExecResult
75+
:param timeout: timeout for command
76+
:type timeout: typing.Union[int, float]
77+
"""
78+
self.result = result
79+
self.timeout = timeout
80+
message = _log_templates.CMD_WAIT_ERROR.format(
81+
result=result,
82+
timeout=timeout
83+
)
84+
super(ExecHelperTimeoutError, self).__init__(message)
85+
86+
@property
87+
def cmd(self): # type: () -> str
88+
"""Failed command."""
89+
return self.result.cmd
90+
91+
@property
92+
def stdout(self): # type: () -> typing.Text
93+
"""Command stdout."""
94+
return self.result.stdout_str
95+
96+
@property
97+
def stderr(self): # type: () -> typing.Text
98+
"""Command stderr."""
99+
return self.result.stderr_str
57100

58101

59102
class CalledProcessError(ExecCalledProcessError):
@@ -74,9 +117,7 @@ def __init__(
74117
:param result: execution result
75118
:type result: exec_result.ExecResult
76119
:param expected: expected return codes
77-
:type expected: typing.Optional[
78-
typing.List[typing.Union[int, proc_enums.ExitCodes]]
79-
]
120+
:type expected: typing.Optional[typing.List[typing.Union[int, proc_enums.ExitCodes]]]
80121
81122
.. versionchanged:: 1.1.1 - provide full result
82123
"""
@@ -89,7 +130,7 @@ def __init__(
89130
"\tSTDOUT:\n"
90131
"{result.stdout_brief}\n"
91132
"\tSTDERR:\n{result.stderr_brief}".format(
92-
result=result,
133+
result=self.result,
93134
expected=self.expected
94135
)
95136
)

exec_helpers/exceptions.pyi

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,32 @@ class ExecHelperError(Exception):
77
class DeserializeValueError(ExecHelperError, ValueError):
88
...
99

10-
class ExecHelperTimeoutError(ExecHelperError):
11-
...
1210

1311
class ExecCalledProcessError(ExecHelperError):
1412
...
1513

1614

15+
class ExecHelperTimeoutError(ExecCalledProcessError):
16+
17+
result: exec_result.ExecResult = ...
18+
timeout: int = ...
19+
20+
def __init__(
21+
self,
22+
result: exec_result.ExecResult,
23+
timeout: typing.Union[int, float],
24+
) -> None: ...
25+
26+
@property
27+
def cmd(self) -> str: ...
28+
29+
@property
30+
def stdout(self) -> typing.Text: ...
31+
32+
@property
33+
def stderr(self) -> typing.Text: ...
34+
35+
1736
class CalledProcessError(ExecCalledProcessError):
1837

1938
result: exec_result.ExecResult = ...

exec_helpers/subprocess_runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def poll_pipes(stop, ): # type: (threading.Event) -> None
269269
timeout=timeout
270270
)
271271
logger.debug(wait_err_msg)
272-
raise exceptions.ExecHelperTimeoutError(wait_err_msg)
272+
raise exceptions.ExecHelperTimeoutError(result=result, timeout=timeout)
273273

274274
def execute_async(
275275
self,

test/test_ssh_client.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,10 +1028,15 @@ def test_025_execute_timeout_fail(
10281028

10291029
logger.reset_mock()
10301030

1031-
with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
1031+
with self.assertRaises(exec_helpers.ExecHelperTimeoutError) as cm:
10321032
# noinspection PyTypeChecker
10331033
ssh.execute(command=command, verbose=False, timeout=0.2)
10341034

1035+
self.assertEqual(cm.exception.timeout, 0.2)
1036+
self.assertEqual(cm.exception.cmd, command)
1037+
self.assertEqual(cm.exception.stdout, stdout_str)
1038+
self.assertEqual(cm.exception.stderr, stderr_str)
1039+
10351040
execute_async.assert_called_once_with(command, verbose=False)
10361041
chan.assert_has_calls((mock.call.status_event.is_set(), ))
10371042

test/test_subprocess_runner.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,15 @@ def test_004_execute_timeout_fail(
233233

234234
# noinspection PyTypeChecker
235235

236-
with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
236+
with self.assertRaises(exec_helpers.ExecHelperTimeoutError) as cm:
237237
# noinspection PyTypeChecker
238238
runner.execute(command, timeout=0.2)
239239

240+
self.assertEqual(cm.exception.timeout, 0.2)
241+
self.assertEqual(cm.exception.cmd, command)
242+
self.assertEqual(cm.exception.stdout, exp_result.stdout_str)
243+
self.assertEqual(cm.exception.stderr, exp_result.stderr_str)
244+
240245
popen.assert_has_calls((
241246
mock.call(
242247
args=[command],

0 commit comments

Comments
 (0)