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
14 changes: 1 addition & 13 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -315,19 +315,7 @@ Kwargs set properties:
Testing
=======
The main test mechanism for the package `exec-helpers` is using `tox`.
Test environments available:

::

pep8
py27
py34
py35
py36
pypy
pypy3
pylint
pep257
Available environments can be collected via `tox -l`

CI systems
==========
Expand Down
2 changes: 1 addition & 1 deletion doc/source/SSHClient.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ API: SSHClient and SSHAuth.
:param log_mask_re: regex lookup rule to mask command for logger.
all MATCHED groups will be replaced by '<*masked*>'
:type log_mask_re: typing.Optional[str]
:rtype: ``typing.Tuple[paramiko.Channel, paramiko.ChannelFile, paramiko.ChannelFile, paramiko.ChannelFile]``
:rtype: ``typing.Tuple[paramiko.Channel, paramiko.ChannelFile, typing.Optional[paramiko.ChannelFile], typing.Optional[paramiko.ChannelFile]]``

.. versionchanged:: 1.2.0 open_stdout and open_stderr flags
.. versionchanged:: 1.2.0 stdin data
Expand Down
2 changes: 1 addition & 1 deletion doc/source/Subprocess.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ API: Subprocess
:param log_mask_re: regex lookup rule to mask command for logger.
all MATCHED groups will be replaced by '<*masked*>'
:type log_mask_re: typing.Optional[str]
:rtype: ``typing.Tuple[subprocess.Popen, None, typing.Optional[io.TextIOWrapper], typing.Optional[io.TextIOWrapper], ]``
:rtype: ``typing.Tuple[subprocess.Popen, None, typing.Optional[typing.IO], typing.Optional[typing.IO], ]``

.. versionadded:: 1.2.0

Expand Down
17 changes: 10 additions & 7 deletions exec_helpers/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import logging
import re
import threading
import typing # noqa # pylint: disable=unused-import
import typing

import six # noqa # pylint: disable=unused-import

Expand All @@ -35,6 +35,9 @@
from exec_helpers import proc_enums
from exec_helpers import _log_templates

_type_exit_codes = typing.Union[int, proc_enums.ExitCodes]
_type_expected = typing.Optional[typing.Iterable[_type_exit_codes]]


class ExecHelper(object):
"""ExecHelper global API."""
Expand Down Expand Up @@ -171,9 +174,9 @@ def execute_async(
def _exec_command(
self,
command, # type: str
interface, # type: typing.Any,
stdout, # type: typing.Any,
stderr, # type: typing.Any,
interface, # type: typing.Any
stdout, # type: typing.Any
stderr, # type: typing.Any
timeout, # type: int
verbose=False, # type: bool
log_mask_re=None, # type: typing.Optional[str]
Expand Down Expand Up @@ -227,10 +230,10 @@ def execute(
"""
with self.lock:
(
iface, # type: typing.Any
iface,
_,
stderr, # type: typing.Any
stdout, # type: typing.Any
stderr,
stdout,
) = self.execute_async(
command,
verbose=verbose,
Expand Down
41 changes: 21 additions & 20 deletions exec_helpers/_ssh_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
_type_execute_async = typing.Tuple[
paramiko.Channel,
paramiko.ChannelFile,
paramiko.ChannelFile,
paramiko.ChannelFile
typing.Optional[paramiko.ChannelFile],
typing.Optional[paramiko.ChannelFile]
]

CPYTHON = 'CPython' == platform.python_implementation()
Expand Down Expand Up @@ -101,7 +101,7 @@ class _MemorizedSSH(type):
duplicates is possible.
"""

__cache = {}
__cache = {} # type: typing.Dict[typing.Tuple[str, int], SSHClientBase]

@classmethod
def __prepare__(
Expand Down Expand Up @@ -622,7 +622,7 @@ def poll_pipes(
:type stop: Event
:type channel: paramiko.channel.Channel
"""
while not stop.isSet():
while not stop.is_set():
time.sleep(0.1)
if stdout or stderr:
poll_streams(result=result)
Expand Down Expand Up @@ -662,7 +662,7 @@ def poll_pipes(
concurrent.futures.wait([future], timeout)

# Process closed?
if stop_event.isSet():
if stop_event.is_set():
stop_event.clear()
interface.close()
return result
Expand Down Expand Up @@ -764,7 +764,7 @@ def execute_together(
remotes, # type: typing.Iterable[SSHClientBase]
command, # type: str
timeout=constants.DEFAULT_TIMEOUT, # type: typing.Optional[int]
expected=None, # type: typing.Optional[typing.Iterable[]]
expected=None, # type: typing.Optional[typing.Iterable[int]]
raise_on_err=True, # type: bool
**kwargs
): # type: (...) -> _type_multiple_results
Expand All @@ -782,10 +782,8 @@ def execute_together(
:type raise_on_err: bool
:return: dictionary {(hostname, port): result}
:rtype: typing.Dict[typing.Tuple[str, int], exec_result.ExecResult]
:raises ParallelCallProcessError:
Unexpected any code at lest on one target
:raises ParallelCallExceptions:
At lest one exception raised during execution (including timeout)
:raises ParallelCallProcessError: Unexpected any code at lest on one target
:raises ParallelCallExceptions: At lest one exception raised during execution (including timeout)

.. versionchanged:: 1.2.0 default timeout 1 hour
.. versionchanged:: 1.2.0 log_mask_re regex rule for masking cmd
Expand All @@ -796,11 +794,14 @@ def get_result(
): # type: (...) -> exec_result.ExecResult
"""Get result from remote call."""
(
chan, # type: paramiko.channel.Channel
chan,
_,
stderr, # type: paramiko.channel.ChannelFile
stdout, # type: paramiko.channel.ChannelFile
) = remote.execute_async(command, **kwargs)
stderr,
stdout,
) = remote.execute_async(
command,
**kwargs
) # type: _type_execute_async

chan.status_event.wait(timeout)
exit_code = chan.recv_exit_status()
Expand Down Expand Up @@ -832,19 +833,19 @@ def get_result(
futures[remote] = get_result(remote)

(
_, # type: typing.Set[concurrent.futures.Future]
not_done, # type: typing.Set[concurrent.futures.Future]
_,
not_done,
) = concurrent.futures.wait(
list(futures.values()),
timeout=timeout
)
) # type: typing.Set[concurrent.futures.Future], typing.Set[concurrent.futures.Future]
for future in not_done:
future.cancel()

for (
remote, # type: SSHClientBase
future, # type: concurrent.futures.Future
) in futures.items():
remote,
future,
) in futures.items(): # type: SSHClientBase, concurrent.futures.Future
try:
result = future.result()
results[(remote.hostname, remote.port)] = result
Expand Down
14 changes: 7 additions & 7 deletions exec_helpers/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __init__(
self,
result=None, # type: exec_result.ExecResult
expected=None, # type: typing.Optional[typing.List[_type_exit_codes]]
):
): # type: (...) -> None
"""Exception for error on process calls.

:param result: execution result
Expand Down Expand Up @@ -136,10 +136,10 @@ def __init__(
self,
command, # type: str
exceptions, # type: typing.Dict[typing.Tuple[str, int], Exception]
errors, # type: _type_multiple_results,
results, # type: _type_multiple_results,
errors, # type: _type_multiple_results
results, # type: _type_multiple_results
expected=None, # type: typing.Optional[typing.List[_type_exit_codes]]
):
): # type: (...) -> None
"""Exception raised during parallel call as result of exceptions.

:param command: command
Expand Down Expand Up @@ -190,10 +190,10 @@ class ParallelCallProcessError(ExecCalledProcessError):
def __init__(
self,
command, # type: str
errors, # type: _type_multiple_results,
results, # type: _type_multiple_results,
errors, # type: _type_multiple_results
results, # type: _type_multiple_results
expected=None, # type: typing.Optional[typing.List[_type_exit_codes]]
):
): # type: (...) -> None
"""Exception during parallel execution.

:param command: command
Expand Down
12 changes: 6 additions & 6 deletions exec_helpers/exec_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __init__(
stdout=None, # type: typing.Optional[typing.Iterable[bytes]]
stderr=None, # type: typing.Optional[typing.Iterable[bytes]]
exit_code=proc_enums.ExitCodes.EX_INVALID # type: _type_exit_codes
):
): # type: (...) -> None
"""Command execution result.

:param cmd: command
Expand All @@ -77,8 +77,8 @@ def __init__(
elif isinstance(stdin, bytearray):
stdin = self._get_str_from_bin(stdin)
self.__stdin = stdin
self.__stdout = tuple(stdout) if stdout is not None else ()
self.__stderr = tuple(stderr) if stderr is not None else ()
self.__stdout = tuple(stdout) if stdout is not None else () # type: typing.Tuple[bytes]
self.__stderr = tuple(stderr) if stderr is not None else () # type: typing.Tuple[bytes]

self.__exit_code = None
self.__timestamp = None
Expand All @@ -99,7 +99,7 @@ def lock(self): # type: () -> threading.RLock
return self.__lock

@property
def timestamp(self): # type: () -> typing.Optional(datetime.datetime)
def timestamp(self): # type: () -> typing.Optional[datetime.datetime]
"""Timestamp.

:rtype: typing.Optional(datetime.datetime)
Expand Down Expand Up @@ -133,10 +133,10 @@ def _get_str_from_bin(src): # type: (bytearray) -> str
def _get_brief(cls, data): # type: (typing.Tuple[bytes]) -> str
"""Get brief output: 7 lines maximum (3 first + ... + 3 last).

:type data: typing.List[bytes]
:type data: typing.Tuple[bytes]
:rtype: str
"""
src = data if len(data) <= 7 else data[:3] + (b'...\n',) + data[-3:]
src = data if len(data) <= 7 else data[:3] + (b'...\n',) + data[-3:] # type: typing.Tuple[bytes]
return cls._get_str_from_bin(
cls._get_bytearray_from_array(src)
)
Expand Down
2 changes: 1 addition & 1 deletion exec_helpers/proc_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def exit_code_to_enum(code): # type: (_type_exit_codes) -> _type_exit_codes


def exit_codes_to_enums(
codes=None # type: typing.Optional[typing.List[_type_exit_codes]]
codes=None # type: typing.Optional[typing.Iterable[_type_exit_codes]]
): # type: (...) -> typing.List[_type_exit_codes]
"""Convert integer exit codes to enums."""
if codes is None:
Expand Down
8 changes: 4 additions & 4 deletions exec_helpers/ssh_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ def __init__(
username=None, # type: typing.Optional[str]
password=None, # type: typing.Optional[str]
key=None, # type: typing.Optional[paramiko.RSAKey]
keys=None, # type: typing.Optional[typing.Iterable[paramiko.RSAKey]],
keys=None, # type: typing.Optional[typing.Iterable[paramiko.RSAKey]]
key_filename=None, # type: typing.Union[typing.List[str], str, None]
passphrase=None, # type: typing.Optional[str]
):
): # type: (...) -> None
"""SSH credentials object.

Used to authorize SSHClient.
Expand Down Expand Up @@ -137,7 +137,7 @@ def enter_password(self, tgt): # type: (io.StringIO) -> None
:type tgt: file
"""
# noinspection PyTypeChecker
return tgt.write('{}\n'.format(self.__password))
tgt.write('{}\n'.format(self.__password))

def connect(
self,
Expand Down Expand Up @@ -166,7 +166,7 @@ def connect(
'password': self.__password,
'key_filename': self.key_filename,
'passphrase': self.__passphrase,
}
} # type: typing.Dict[str, typing.Any]
if hostname is not None:
kwargs['hostname'] = hostname
kwargs['port'] = port
Expand Down
Loading