Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions doc/source/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,45 @@ API: exceptions

Deserialize impossible.

.. py:exception:: ExecHelperTimeoutError(ExecHelperError)
.. py:exception:: ExecCalledProcessError(ExecHelperError)

Base class for process call errors.

.. py:exception:: ExecHelperTimeoutError(ExecCalledProcessError)

Execution timeout.

.. py:exception:: ExecCalledProcessError(ExecHelperError)
.. versionchanged:: 1.3.0 provide full result and timeout inside.
.. versionchanged:: 1.3.0 subclass ExecCalledProcessError

Base class for process call errors.
.. py:method:: __init__(self, result, timeout)

Exception for error on process calls.

:param result: execution result
:type result: exec_result.ExecResult
:param timeout: timeout for command
:type timeout: typing.Union[int, float]

.. py:attribute:: timeout

``int``

.. py:attribute:: result

Execution result

:rtype: ExecResult

.. py:attribute:: stdout

``typing.Text``
stdout string or brief string

.. py:attribute:: stderr

``typing.Text``
stdout string or brief string

.. py:exception:: CalledProcessError(ExecCalledProcessError)

Expand Down Expand Up @@ -60,12 +92,12 @@ API: exceptions

.. py:attribute:: stdout

``typing.Any``
``typing.Text``
stdout string or brief string

.. py:attribute:: stderr

``typing.Any``
``typing.Text``
stdout string or brief string

.. py:exception:: ParallelCallExceptions(ExecCalledProcessError)
Expand Down
2 changes: 1 addition & 1 deletion exec_helpers/_ssh_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ def poll_pipes(stop, ): # type: (threading.Event) -> None
timeout=timeout
)
self.logger.debug(wait_err_msg)
raise exceptions.ExecHelperTimeoutError(wait_err_msg)
raise exceptions.ExecHelperTimeoutError(result=result, timeout=timeout)

def execute_through_host(
self,
Expand Down
59 changes: 50 additions & 9 deletions exec_helpers/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import typing # noqa # pylint: disable=unused-import

from exec_helpers import proc_enums
from exec_helpers import _log_templates

__all__ = (
'ExecHelperError',
Expand All @@ -44,16 +45,58 @@ class DeserializeValueError(ExecHelperError, ValueError):
__slots__ = ()


class ExecHelperTimeoutError(ExecHelperError):
"""Execution timeout."""
class ExecCalledProcessError(ExecHelperError):
"""Base class for process call errors."""

__slots__ = ()


class ExecCalledProcessError(ExecHelperError):
"""Base class for process call errors."""
class ExecHelperTimeoutError(ExecCalledProcessError):
"""Execution timeout.

__slots__ = ()
.. versionchanged:: 1.3.0 provide full result and timeout inside.
.. versionchanged:: 1.3.0 subclass ExecCalledProcessError
"""

__slots__ = (
'result',
'timeout',
)

def __init__(
self,
result, # type: exec_result.ExecResult
timeout, # type: typing.Union[int, float]
): # type: (...) -> None
"""Exception for error on process calls.

:param result: execution result
:type result: exec_result.ExecResult
:param timeout: timeout for command
:type timeout: typing.Union[int, float]
"""
self.result = result
self.timeout = timeout
message = _log_templates.CMD_WAIT_ERROR.format(
result=result,
timeout=timeout
)
super(ExecHelperTimeoutError, self).__init__(message)

@property
def cmd(self): # type: () -> str
"""Failed command."""
return self.result.cmd

@property
def stdout(self): # type: () -> typing.Text
"""Command stdout."""
return self.result.stdout_str

@property
def stderr(self): # type: () -> typing.Text
"""Command stderr."""
return self.result.stderr_str


class CalledProcessError(ExecCalledProcessError):
Expand All @@ -74,9 +117,7 @@ def __init__(
:param result: execution result
:type result: exec_result.ExecResult
:param expected: expected return codes
:type expected: typing.Optional[
typing.List[typing.Union[int, proc_enums.ExitCodes]]
]
:type expected: typing.Optional[typing.List[typing.Union[int, proc_enums.ExitCodes]]]

.. versionchanged:: 1.1.1 - provide full result
"""
Expand All @@ -89,7 +130,7 @@ def __init__(
"\tSTDOUT:\n"
"{result.stdout_brief}\n"
"\tSTDERR:\n{result.stderr_brief}".format(
result=result,
result=self.result,
expected=self.expected
)
)
Expand Down
23 changes: 21 additions & 2 deletions exec_helpers/exceptions.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,32 @@ class ExecHelperError(Exception):
class DeserializeValueError(ExecHelperError, ValueError):
...

class ExecHelperTimeoutError(ExecHelperError):
...

class ExecCalledProcessError(ExecHelperError):
...


class ExecHelperTimeoutError(ExecCalledProcessError):

result: exec_result.ExecResult = ...
timeout: int = ...

def __init__(
self,
result: exec_result.ExecResult,
timeout: typing.Union[int, float],
) -> None: ...

@property
def cmd(self) -> str: ...

@property
def stdout(self) -> typing.Text: ...

@property
def stderr(self) -> typing.Text: ...


class CalledProcessError(ExecCalledProcessError):

result: exec_result.ExecResult = ...
Expand Down
2 changes: 1 addition & 1 deletion exec_helpers/subprocess_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def poll_pipes(stop, ): # type: (threading.Event) -> None
timeout=timeout
)
logger.debug(wait_err_msg)
raise exceptions.ExecHelperTimeoutError(wait_err_msg)
raise exceptions.ExecHelperTimeoutError(result=result, timeout=timeout)

def execute_async(
self,
Expand Down
7 changes: 6 additions & 1 deletion test/test_ssh_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1028,10 +1028,15 @@ def test_025_execute_timeout_fail(

logger.reset_mock()

with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
with self.assertRaises(exec_helpers.ExecHelperTimeoutError) as cm:
# noinspection PyTypeChecker
ssh.execute(command=command, verbose=False, timeout=0.2)

self.assertEqual(cm.exception.timeout, 0.2)
self.assertEqual(cm.exception.cmd, command)
self.assertEqual(cm.exception.stdout, stdout_str)
self.assertEqual(cm.exception.stderr, stderr_str)

execute_async.assert_called_once_with(command, verbose=False)
chan.assert_has_calls((mock.call.status_event.is_set(), ))

Expand Down
7 changes: 6 additions & 1 deletion test/test_subprocess_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,15 @@ def test_004_execute_timeout_fail(

# noinspection PyTypeChecker

with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
with self.assertRaises(exec_helpers.ExecHelperTimeoutError) as cm:
# noinspection PyTypeChecker
runner.execute(command, timeout=0.2)

self.assertEqual(cm.exception.timeout, 0.2)
self.assertEqual(cm.exception.cmd, command)
self.assertEqual(cm.exception.stdout, exp_result.stdout_str)
self.assertEqual(cm.exception.stderr, exp_result.stderr_str)

popen.assert_has_calls((
mock.call(
args=[command],
Expand Down