diff --git a/.travis.yml b/.travis.yml index c05b2a9..04d2c15 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,17 +22,16 @@ jobs: include: - stage: Static analisys python: 3.6 - services: skip + services: [] install: - *upgrade_python_toolset - pip install tox script: - - tox -e pylint,bandit + - tox -e pylint,bandit,mypy after_success: skip - stage: Code style check python: *mainstream_python - services: skip install: - *upgrade_python_toolset - pip install tox @@ -45,8 +44,7 @@ jobs: if: tag IS present # Run on pypy to build not cythonized wheel python: *pypy - services: - - docker + services: [] install: - *upgrade_python_toolset script: diff --git a/exec_helpers/__init__.py b/exec_helpers/__init__.py index 95e3152..53fbadb 100644 --- a/exec_helpers/__init__.py +++ b/exec_helpers/__init__.py @@ -28,6 +28,7 @@ ) from .exec_result import ExecResult +from .api import ExecHelper from .ssh_auth import SSHAuth from .ssh_client import SSHClient from .subprocess_runner import Subprocess # nosec # Expected @@ -39,6 +40,7 @@ 'ParallelCallExceptions', 'ParallelCallProcessError', 'ExecHelperTimeoutError', + 'ExecHelper', 'SSHClient', 'SSHAuth', 'Subprocess', diff --git a/exec_helpers/_ssh_client_base.py b/exec_helpers/_ssh_client_base.py index 253a39e..068a31e 100644 --- a/exec_helpers/_ssh_client_base.py +++ b/exec_helpers/_ssh_client_base.py @@ -40,7 +40,7 @@ import threaded import six -from exec_helpers import _api +from exec_helpers import api from exec_helpers import constants from exec_helpers import exec_result from exec_helpers import exceptions @@ -97,10 +97,10 @@ class _MemorizedSSH(type): @classmethod def __prepare__( - mcs, + mcs, # type: typing.Type[_MemorizedSSH] name, # type: str bases, # type: typing.Iterable[typing.Type] - **kwargs + **kwargs # type: typing.Dict ): # type: (...) -> collections.OrderedDict # pylint: disable=unused-argument """Metaclass magic for object storage. @@ -109,7 +109,7 @@ def __prepare__( return collections.OrderedDict() # pragma: no cover def __call__( - cls, + cls, # type: _MemorizedSSH host, # type: str port=22, # type: int username=None, # type: typing.Optional[str] @@ -167,7 +167,7 @@ def __call__( return ssh @classmethod - def clear_cache(mcs): # type: () -> None + def clear_cache(mcs): # type: (typing.Type[_MemorizedSSH]) -> None """Clear cached connections for initialize new instance on next call. getrefcount is used to check for usage. @@ -185,14 +185,14 @@ def clear_cache(mcs): # type: () -> None mcs.__cache = {} @classmethod - def close_connections(mcs): # type: (...) -> None + def close_connections(mcs): # type: (typing.Type[_MemorizedSSH]) -> None """Close connections for selected or all cached records.""" for ssh in mcs.__cache.values(): if ssh.is_alive: ssh.close() -class SSHClientBase(six.with_metaclass(_MemorizedSSH, _api.ExecHelper)): +class SSHClientBase(six.with_metaclass(_MemorizedSSH, api.ExecHelper)): """SSH Client helper.""" __slots__ = ( @@ -454,7 +454,9 @@ def close(self): # noinspection PyMethodParameters @close.class_method - def close(cls): # pylint: disable=no-self-argument + def close( # pylint: disable=no-self-argument + cls # type: typing.Type[SSHClientBase] + ): # type: (...) -> None """Close all memorized SSH and SFTP sessions.""" # noinspection PyUnresolvedReferences cls.__class__.close_connections() diff --git a/exec_helpers/_ssh_client_base.pyi b/exec_helpers/_ssh_client_base.pyi index 16b52c6..6325d83 100644 --- a/exec_helpers/_ssh_client_base.pyi +++ b/exec_helpers/_ssh_client_base.pyi @@ -3,15 +3,17 @@ import typing import paramiko # type: ignore -from exec_helpers import exec_result, ssh_auth, _api +from exec_helpers import exec_result, ssh_auth, api + +CPYTHON: bool = ... class _MemorizedSSH(type): @classmethod - def __prepare__(mcs: typing.Type, name: str, bases: typing.Iterable[typing.Type], **kwargs: typing.Dict) -> collections.OrderedDict: ... + def __prepare__(mcs: typing.Type[_MemorizedSSH], name: str, bases: typing.Iterable[typing.Type], **kwargs: typing.Dict) -> collections.OrderedDict: ... def __call__( # type: ignore - cls: typing.Type[SSHClientBase], + cls: _MemorizedSSH, host: str, port: int=..., username: typing.Optional[str]=..., @@ -22,13 +24,13 @@ class _MemorizedSSH(type): ) -> SSHClientBase: ... @classmethod - def clear_cache(mcs: typing.Type[SSHClientBase]) -> None: ... # type: ignore + def clear_cache(mcs: typing.Type[_MemorizedSSH]) -> None: ... @classmethod - def close_connections(mcs: typing.Type[SSHClientBase]) -> None: ... # type: ignore + def close_connections(mcs: typing.Type[_MemorizedSSH]) -> None: ... -class SSHClientBase(_api.ExecHelper, metaclass=_MemorizedSSH): +class SSHClientBase(api.ExecHelper, metaclass=_MemorizedSSH): def __hash__(self) -> int: ... def __init__( @@ -65,7 +67,7 @@ class SSHClientBase(_api.ExecHelper, metaclass=_MemorizedSSH): def _sftp(self) -> paramiko.sftp_client.SFTPClient: ... @classmethod - def close(cls) -> None: ... + def close(cls: typing.Union[SSHClientBase, typing.Type[SSHClientBase]]) -> None: ... @classmethod def _clear_cache(cls) -> None: ... diff --git a/exec_helpers/_api.py b/exec_helpers/api.py similarity index 98% rename from exec_helpers/_api.py rename to exec_helpers/api.py index 07d61f1..8c55bb4 100644 --- a/exec_helpers/_api.py +++ b/exec_helpers/api.py @@ -16,6 +16,7 @@ """ExecHelpers global API. .. versionadded:: 1.2.0 +.. versionchanged:: 1.3.5 make API public to use as interface """ from __future__ import absolute_import @@ -54,6 +55,7 @@ def __init__( :type log_mask_re: typing.Optional[str] .. versionchanged:: 1.2.0 log_mask_re regex rule for masking cmd + .. versionchanged:: 1.3.5 make API public to use as interface """ self.__lock = threading.RLock() self.__logger = logger diff --git a/exec_helpers/_api.pyi b/exec_helpers/api.pyi similarity index 100% rename from exec_helpers/_api.pyi rename to exec_helpers/api.pyi diff --git a/exec_helpers/subprocess_runner.py b/exec_helpers/subprocess_runner.py index b36a05c..ca13d04 100644 --- a/exec_helpers/subprocess_runner.py +++ b/exec_helpers/subprocess_runner.py @@ -36,7 +36,7 @@ import six import threaded -from exec_helpers import _api +from exec_helpers import api from exec_helpers import exec_result from exec_helpers import exceptions from exec_helpers import _log_templates @@ -122,7 +122,7 @@ def set_nonblocking_pipe(pipe): # type: (typing.Any) -> None ) -class Subprocess(six.with_metaclass(SingletonMeta, _api.ExecHelper)): +class Subprocess(six.with_metaclass(SingletonMeta, api.ExecHelper)): """Subprocess helper with timeouts and lock-free FIFO.""" def __init__( diff --git a/exec_helpers/subprocess_runner.pyi b/exec_helpers/subprocess_runner.pyi index ced1f29..016ebc7 100644 --- a/exec_helpers/subprocess_runner.pyi +++ b/exec_helpers/subprocess_runner.pyi @@ -4,7 +4,7 @@ import subprocess import threading import typing -from exec_helpers import exec_result, _api +from exec_helpers import exec_result, api logger: logging.Logger devnull: typing.IO @@ -16,16 +16,16 @@ class SingletonMeta(type): _instances: typing.Dict[typing.Type, typing.Any] = ... _lock: threading.RLock = ... - def __call__(cls: typing.Type, *args: typing.Tuple, **kwargs: typing.Dict) -> typing.Any: ... + def __call__(cls: SingletonMeta, *args: typing.Tuple, **kwargs: typing.Dict) -> typing.Any: ... @classmethod - def __prepare__(mcs: typing.Type, name: str, bases: typing.Iterable[typing.Type], **kwargs: typing.Dict) -> collections.OrderedDict: ... + def __prepare__(mcs: typing.Type[SingletonMeta], name: str, bases: typing.Iterable[typing.Type], **kwargs: typing.Dict) -> collections.OrderedDict: ... def set_nonblocking_pipe(pipe: typing.Any) -> None: ... -class Subprocess(_api.ExecHelper, metaclass=SingletonMeta): +class Subprocess(api.ExecHelper, metaclass=SingletonMeta): def __init__( self, log_mask_re: typing.Optional[str]=... diff --git a/setup.py b/setup.py index 34af296..d959910 100644 --- a/setup.py +++ b/setup.py @@ -64,7 +64,7 @@ def _extension(modpath): requires_optimization = [ - _extension('exec_helpers._api'), + _extension('exec_helpers.api'), _extension('exec_helpers.constants'), _extension('exec_helpers._log_templates'), _extension('exec_helpers.exceptions'), diff --git a/tox.ini b/tox.ini index 2b7a63f..248dad5 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ [tox] minversion = 2.0 -envlist = pep8, pep257, py{27,34,35,36,37,py,py3}, pylint, bandit, py{34,35,36,37}-nocov, docs, +envlist = pep8, pep257, py{27,34,35,36,37,py,py3}, pylint, bandit, py{34,35,36,37}-nocov, mypy, docs skipsdist = True skip_missing_interpreters = True