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
2 changes: 1 addition & 1 deletion doc/source/SSHClient.rst
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ API: SSHClient and SSHAuth.
Execute command on multiple remotes in async mode.

:param remotes: Connections to execute on
:type remotes: ``typing.Iterable[SSHClientBase]``
:type remotes: typing.Iterable[SSHClient]
:param command: Command for execution
:type command: ``str``
:param timeout: Timeout for command execution.
Expand Down
58 changes: 34 additions & 24 deletions doc/source/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,20 @@ API: exceptions

Exception for error on process calls.

.. py:method:: __init__(command, returncode, expected=None, stdout=None, stderr=None)
.. versionchanged:: 1.1.1 - provide full result

:param command: command
:type command: str
.. py:method:: __init__(result, expected=None)

:param result: execution result
:type result: ExecResult
:param returncode: return code
:type returncode: typing.Union[int, proc_enums.ExitCodes]
:param expected: expected return codes
:type expected: typing.Optional[typing.List[typing.Union[int, proc_enums.ExitCodes]]]
:param stdout: stdout string or brief string
:type stdout: typing.Any
:param stderr: stderr string or brief string
:type stderr: typing.Any
:type returncode: typing.Union[int, ExitCodes]

.. py:attribute:: result

Execution result

:rtype: ExecResult

.. py:attribute:: cmd

Expand All @@ -42,14 +44,16 @@ API: exceptions

.. py:attribute:: returncode

``typing.Union[int, proc_enums.ExitCodes]``
return code

:rtype: typing.Union[int, ExitCodes]

.. py:attribute:: expected

``typing.List[typing.Union[int, proc_enums.ExitCodes]]``
expected return codes

:rtype: typing.List[typing.Union[int, ExitCodes]]

.. py:attribute:: stdout

``typing.Any``
Expand All @@ -71,11 +75,11 @@ API: exceptions
:param exceptions: Exception on connections
:type exceptions: ``typing.Dict[typing.Tuple[str, int], Exception]``
:param errors: results with errors
:type errors: ``typing.Dict[typing.Tuple[str, int], ExecResult]``
:type errors: typing.Dict[typing.Tuple[str, int], ExecResult]
:param results: all results
:type results: ``typing.Dict[typing.Tuple[str, int], ExecResult]``
:type results: typing.Dict[typing.Tuple[str, int], ExecResult]
:param expected: expected return codes
:type expected: ``typing.Optional[typing.List[typing.List[typing.Union[int, proc_enums.ExitCodes]]]``
:type expected: typing.Optional[typing.List[typing.List[typing.Union[int, ExitCodes]]]

.. versionchanged:: 1.0 - fixed inheritance

Expand All @@ -91,19 +95,22 @@ API: exceptions

.. py:attribute:: errors

``typing.Dict[typing.Tuple[str, int], ExecResult]``
results with errors

:rtype: typing.Dict[typing.Tuple[str, int], ExecResult]

.. py:attribute:: results

``typing.Dict[typing.Tuple[str, int], ExecResult]``
all results

:rtype: typing.Dict[typing.Tuple[str, int], ExecResult]

.. py:attribute:: expected

``typing.List[typing.Union[int, proc_enums.ExitCodes]]``
expected return codes

:rtype: typing.List[typing.Union[int, ExitCodes]]

.. py:exception:: ParallelCallProcessError(ExecCalledProcessError)

Exception during parallel execution.
Expand All @@ -113,11 +120,11 @@ API: exceptions
:param command: command
:type command: ``str``
:param errors: results with errors
:type errors: ``typing.Dict[typing.Tuple[str, int], ExecResult]``
:type errors: typing.Dict[typing.Tuple[str, int], ExecResult]
:param results: all results
:type results: ``typing.Dict[typing.Tuple[str, int], ExecResult]``
:type results: typing.Dict[typing.Tuple[str, int], ExecResult]
:param expected: expected return codes
:type expected: ``typing.Optional[typing.List[typing.List[typing.Union[int, proc_enums.ExitCodes]]]``
:type expected: typing.Optional[typing.List[typing.List[typing.Union[int, ExitCodes]]]

.. versionchanged:: 1.0 - fixed inheritance

Expand All @@ -128,15 +135,18 @@ API: exceptions

.. py:attribute:: errors

``typing.Dict[typing.Tuple[str, int], ExecResult]``
results with errors

:rtype: typing.Dict[typing.Tuple[str, int], ExecResult]

.. py:attribute:: results

``typing.Dict[typing.Tuple[str, int], ExecResult]``
all results

:rtype: typing.Dict[typing.Tuple[str, int], ExecResult]

.. py:attribute:: expected

``typing.List[typing.Union[int, proc_enums.ExitCodes]]``
expected return codes

:rtype: typing.List[typing.Union[int, ExitCodes]]
15 changes: 5 additions & 10 deletions exec_helpers/_ssh_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ def close_connections(mcs, hostname=None):
mcs.__cache[key].close()


def _py2_str(src):
def _py2_str(src): # pragma: no cover
"""Convert text to correct python type."""
if not six.PY3 and isinstance(src, six.text_type):
return src.encode(
Expand Down Expand Up @@ -696,7 +696,7 @@ def __del__(self):
"""
try:
self.__ssh.close()
except BaseException as e:
except BaseException as e: # pragma: no cover
self.logger.debug(
'Exception in {self!s} destructor call: {exc}'.format(
self=self,
Expand Down Expand Up @@ -986,10 +986,8 @@ def check_call(
self.logger.error(message)
if raise_on_err:
raise exceptions.CalledProcessError(
command, ret.exit_code,
expected=expected,
stdout=ret.stdout_brief,
stderr=ret.stderr_brief
result=ret,
expected=expected
)
return ret

Expand Down Expand Up @@ -1031,11 +1029,8 @@ def check_stderr(
self.logger.error(message)
if raise_on_err:
raise exceptions.CalledProcessError(
command,
ret.exit_code,
result=ret,
expected=kwargs.get('expected'),
stdout=ret.stdout_brief,
stderr=ret.stderr_brief
)
return ret

Expand Down
77 changes: 37 additions & 40 deletions exec_helpers/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

import typing

import six

from exec_helpers import proc_enums

__all__ = (
Expand Down Expand Up @@ -52,69 +50,68 @@ class ExecCalledProcessError(ExecHelperError):

__slots__ = ()

@staticmethod
def _makestr(data): # type: (typing.Any) -> six.text_type
"""Make string from object."""
if isinstance(data, six.binary_type):
return data.decode('utf-8', errors='backslashreplace')
elif isinstance(data, six.text_type):
return data
return repr(data)


class CalledProcessError(ExecCalledProcessError):
"""Exception for error on process calls."""

__slots__ = (
'cmd',
'returncode',
'result',
'expected',
'stdout',
'stderr'
)

def __init__(
self,
command, # type: str
returncode, # type: typing.Union[int, proc_enums.ExitCodes]
result=None, # type: exec_result.ExecResult
expected=None, # type: typing.Optional[typing.List[_type_exit_codes]]
stdout=None, # type: typing.Any
stderr=None # type: typing.Any
):
"""Exception for error on process calls.

:param command: command
:type command: str
:param returncode: return code
:type returncode: typing.Union[int, proc_enums.ExitCodes]
: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]]
]
:param stdout: stdout string or brief string
:type stdout: typing.Any
:param stderr: stderr string or brief string
:type stderr: typing.Any

.. versionchanged:: 1.1.1 - provide full result
"""
self.returncode = returncode
self.result = result
expected = expected or [proc_enums.ExitCodes.EX_OK]
self.expected = proc_enums.exit_codes_to_enums(expected)
self.cmd = command
self.stdout = stdout
self.stderr = stderr
message = (
"Command {cmd!r} returned exit code {code} while "
"expected {expected}".format(
cmd=self._makestr(self.cmd),
code=self.returncode,
"Command {result.cmd!r} returned exit code {result.exit_code} "
"while expected {expected}\n"
"\tSTDOUT:\n"
"{result.stdout_brief}\n"
"\tSTDERR:\n{result.stderr_brief}".format(
result=result,
expected=self.expected
))
if self.stdout:
message += "\n\tSTDOUT:\n{}".format(self._makestr(self.stdout))
if self.stderr:
message += "\n\tSTDERR:\n{}".format(self._makestr(self.stderr))
)
)
super(CalledProcessError, self).__init__(message)

@property
def returncode(
self
): # type: () -> typing.Union[int, proc_enums.ExitCodes]
"""Command return code."""
return self.result.exit_code

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

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

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


class ParallelCallExceptions(ExecCalledProcessError):
"""Exception raised during parallel call as result of exceptions."""
Expand Down
4 changes: 2 additions & 2 deletions exec_helpers/proc_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ def __str__(self):
)


if six.PY3:
if six.PY3: # pragma: no cover
digit_type = int
else:
else: # pragma: no cover
# noinspection PyUnresolvedReferences
digit_type = long # noqa # pylint: disable=undefined-variable

Expand Down
13 changes: 4 additions & 9 deletions exec_helpers/subprocess_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __call__(cls, *args, **kwargs):
return cls._instances[cls]


def _py2_str(src):
def _py2_str(src): # pragma: no cover
"""Convert text to correct python type."""
if not six.PY3 and isinstance(src, six.text_type):
return src.encode(
Expand Down Expand Up @@ -311,11 +311,9 @@ def check_call(
logger.error(message)
if raise_on_err:
raise exceptions.CalledProcessError(
command,
ret.exit_code,
result=ret,
expected=expected,
stdout=ret.stdout_brief,
stderr=ret.stderr_brief)
)
return ret

def check_stderr(
Expand Down Expand Up @@ -351,10 +349,7 @@ def check_stderr(
logger.error(message)
if raise_on_err:
raise exceptions.CalledProcessError(
command,
ret['exit_code'],
result=ret,
expected=kwargs.get('expected'),
stdout=ret['stdout_brief'],
stderr=ret['stderr_brief'],
)
return ret
Loading