Skip to content

Commit

Permalink
Merge 90b5326 into 42ebef3
Browse files Browse the repository at this point in the history
  • Loading branch information
penguinolog committed May 2, 2018
2 parents 42ebef3 + 90b5326 commit 8a474b8
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 129 deletions.
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

0 comments on commit 8a474b8

Please sign in to comment.