Skip to content

Commit fb61f62

Browse files
committed
Better type annotations, flake8 to include pep257
1 parent 85843cf commit fb61f62

25 files changed

+154
-138
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ jobs:
6666
name: "PEP8"
6767
install:
6868
- *upgrade_python_toolset
69-
- pip install --upgrade flake8 flake8-bugbear
69+
- pip install --upgrade -r flake8_requirements.txt
7070
script:
71-
- flake8
71+
- flake8 exec_helpers
7272

7373
# - <<: *code_style_check
7474
# name: "PEP257"

azure-pipelines.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ jobs:
1515
- script: |
1616
python -m pip install --upgrade pip
1717
pip install -U setuptools virtualenv
18-
pip install -r CI_REQUIREMENTS.txt
19-
pip install -r pytest_requirements.txt
20-
pip install -U pytest-flake8 flake8-bugbear flake8-docstrings
18+
pip install -U -r CI_REQUIREMENTS.txt
19+
pip install -U -r pytest_requirements.txt
20+
pip install -U pytest-flake8
21+
pip install -U -r flake8_requirements.txt
2122
displayName: 'Install dependencies'
2223
2324
- script: |

exec_helpers/_ssh_base.py

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
"""SSH client helper based on Paramiko. Base class."""
1818

19-
__all__ = ("SSHClientBase", "SshExecuteAsyncResult", "normalize_path")
19+
__all__ = ("SSHClientBase", "SshExecuteAsyncResult", "normalize_path", "SupportPathT")
2020

2121
# Standard Library
2222
import concurrent.futures
@@ -45,28 +45,27 @@
4545
from exec_helpers import ssh_auth
4646
from exec_helpers.api import CalledProcessErrorSubClassT
4747
from exec_helpers.api import CommandT
48+
from exec_helpers.api import ExpectedExitCodesT
49+
from exec_helpers.api import LogMaskReT
4850
from exec_helpers.api import OptionalStdinT
4951
from exec_helpers.api import OptionalTimeoutT
5052
from exec_helpers.proc_enums import ExitCodeT # pylint: disable=unused-import
5153

5254
# Local Implementation
5355
from . import _log_templates
5456
from . import _ssh_helpers
55-
from ._ssh_helpers import HostsSSHConfigs
56-
from ._ssh_helpers import SSHConfig
57+
from ._ssh_helpers import SSHConfigsDictT
5758

5859
if typing.TYPE_CHECKING:
5960
import socket
6061

62+
KeepAlivePeriodT = typing.Union[int, bool]
63+
SupportPathT = typing.Union[str, pathlib.PurePath]
6164
_OptionalSSHAuthMapT = typing.Optional[typing.Union[typing.Dict[str, ssh_auth.SSHAuth], ssh_auth.SSHAuthMapping]]
6265
_OptionalSSHConfigArgT = typing.Union[
63-
str,
64-
paramiko.SSHConfig,
65-
typing.Dict[str, typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]],
66-
HostsSSHConfigs,
67-
None,
66+
str, paramiko.SSHConfig, SSHConfigsDictT, _ssh_helpers.HostsSSHConfigs, None,
6867
]
69-
_SSHConnChainT = typing.List[typing.Tuple[SSHConfig, ssh_auth.SSHAuth]]
68+
_SSHConnChainT = typing.List[typing.Tuple[_ssh_helpers.SSHConfig, ssh_auth.SSHAuth]]
7069
_OptSSHAuthT = typing.Optional[ssh_auth.SSHAuth]
7170
_RType = typing.TypeVar("_RType")
7271

@@ -196,9 +195,7 @@ def normalize_path(tgt: typing.Callable[..., _RType]) -> typing.Callable[..., _R
196195
"""
197196

198197
@functools.wraps(tgt)
199-
def wrapper(
200-
self: typing.Any, path: "typing.Union[str, pathlib.PurePath]", *args: typing.Any, **kwargs: typing.Any
201-
) -> _RType:
198+
def wrapper(self: typing.Any, path: SupportPathT, *args: typing.Any, **kwargs: typing.Any) -> _RType:
202199
"""Normalize path type before use in corresponding method.
203200
204201
:param self: owner instance
@@ -299,17 +296,17 @@ def __init__(
299296
ssh_config: _OptionalSSHConfigArgT = None,
300297
ssh_auth_map: _OptionalSSHAuthMapT = None,
301298
sock: "typing.Optional[typing.Union[paramiko.ProxyCommand, paramiko.Channel, socket.socket]]" = None,
302-
keepalive: "typing.Union[int, bool]" = 1,
299+
keepalive: KeepAlivePeriodT = 1,
303300
) -> None:
304301
"""Main SSH Client helper."""
305302
# Init ssh config. It's main source for connection parameters
306-
if isinstance(ssh_config, HostsSSHConfigs):
307-
self.__ssh_config: HostsSSHConfigs = ssh_config
303+
if isinstance(ssh_config, _ssh_helpers.HostsSSHConfigs):
304+
self.__ssh_config: _ssh_helpers.HostsSSHConfigs = ssh_config
308305
else:
309306
self.__ssh_config = _ssh_helpers.parse_ssh_config(ssh_config, host)
310307

311308
# Get config. We are not resolving full chain. If you are have a chain by some reason - init config manually.
312-
config: SSHConfig = self.__ssh_config[host]
309+
config: _ssh_helpers.SSHConfig = self.__ssh_config[host]
313310

314311
# Save resolved hostname and port
315312
self.__hostname: str = config.hostname
@@ -428,7 +425,7 @@ def port(self) -> int:
428425
return self.__port
429426

430427
@property
431-
def ssh_config(self) -> HostsSSHConfigs:
428+
def ssh_config(self) -> _ssh_helpers.HostsSSHConfigs:
432429
"""SSH connection config.
433430
434431
:return: SSH config for connection
@@ -634,7 +631,7 @@ def keepalive_period(self) -> int:
634631
return self.__keepalive_period
635632

636633
@keepalive_period.setter
637-
def keepalive_period(self, period: "typing.Union[int, bool]") -> None:
634+
def keepalive_period(self, period: KeepAlivePeriodT) -> None:
638635
"""Keepalive period change for connection object.
639636
640637
:param period: keepalive period change
@@ -651,7 +648,7 @@ def reconnect(self) -> None:
651648
self.close()
652649
self.__connect()
653650

654-
def sudo(self, enforce: "typing.Optional[bool]" = None) -> "typing.ContextManager[None]":
651+
def sudo(self, enforce: "typing.Optional[bool]" = None) -> _SudoContext:
655652
"""Call contextmanager for sudo mode change.
656653
657654
:param enforce: Enforce sudo enabled or disabled. By default: None
@@ -661,7 +658,7 @@ def sudo(self, enforce: "typing.Optional[bool]" = None) -> "typing.ContextManage
661658
"""
662659
return _SudoContext(ssh=self, enforce=enforce)
663660

664-
def keepalive(self, enforce: "typing.Union[int, bool]" = 1) -> "typing.ContextManager[None]":
661+
def keepalive(self, enforce: KeepAlivePeriodT = 1) -> _KeepAliveContext:
665662
"""Call contextmanager with keepalive period change.
666663
667664
:param enforce: Enforce keepalive period.
@@ -779,6 +776,7 @@ def _execute_async( # pylint: disable=arguments-differ
779776
stdout.close()
780777
res_stdout = None
781778

779+
# noinspection PyArgumentList
782780
return SshExecuteAsyncResult(interface=chan, stdin=_stdin, stderr=stderr, stdout=res_stdout, started=started)
783781

784782
def _exec_command( # type: ignore
@@ -788,7 +786,7 @@ def _exec_command( # type: ignore
788786
timeout: OptionalTimeoutT,
789787
*,
790788
verbose: bool = False,
791-
log_mask_re: "typing.Optional[str]" = None,
789+
log_mask_re: LogMaskReT = None,
792790
stdin: OptionalStdinT = None,
793791
**kwargs: typing.Any,
794792
) -> exec_result.ExecResult:
@@ -868,7 +866,7 @@ def execute( # pylint: disable=arguments-differ
868866
verbose: bool = False,
869867
timeout: OptionalTimeoutT = constants.DEFAULT_TIMEOUT,
870868
*,
871-
log_mask_re: "typing.Optional[str]" = None,
869+
log_mask_re: LogMaskReT = None,
872870
stdin: OptionalStdinT = None,
873871
open_stdout: bool = True,
874872
open_stderr: bool = True,
@@ -930,7 +928,7 @@ def __call__(
930928
verbose: bool = False,
931929
timeout: OptionalTimeoutT = constants.DEFAULT_TIMEOUT,
932930
*,
933-
log_mask_re: "typing.Optional[str]" = None,
931+
log_mask_re: LogMaskReT = None,
934932
stdin: OptionalStdinT = None,
935933
open_stdout: bool = True,
936934
open_stderr: bool = True,
@@ -991,10 +989,10 @@ def check_call( # pylint: disable=arguments-differ
991989
verbose: bool = False,
992990
timeout: OptionalTimeoutT = constants.DEFAULT_TIMEOUT,
993991
error_info: "typing.Optional[str]" = None,
994-
expected: "typing.Iterable[ExitCodeT]" = (proc_enums.EXPECTED,),
992+
expected: ExpectedExitCodesT = (proc_enums.EXPECTED,),
995993
raise_on_err: bool = True,
996994
*,
997-
log_mask_re: "typing.Optional[str]" = None,
995+
log_mask_re: LogMaskReT = None,
998996
stdin: OptionalStdinT = None,
999997
open_stdout: bool = True,
1000998
open_stderr: bool = True,
@@ -1072,8 +1070,8 @@ def check_stderr( # pylint: disable=arguments-differ
10721070
error_info: "typing.Optional[str]" = None,
10731071
raise_on_err: bool = True,
10741072
*,
1075-
expected: "typing.Iterable[ExitCodeT]" = (proc_enums.EXPECTED,),
1076-
log_mask_re: "typing.Optional[str]" = None,
1073+
expected: ExpectedExitCodesT = (proc_enums.EXPECTED,),
1074+
log_mask_re: LogMaskReT = None,
10771075
stdin: OptionalStdinT = None,
10781076
open_stdout: bool = True,
10791077
open_stderr: bool = True,
@@ -1143,7 +1141,7 @@ def check_stderr( # pylint: disable=arguments-differ
11431141
**kwargs,
11441142
)
11451143

1146-
def _get_proxy_channel(self, port: "typing.Optional[int]", ssh_config: SSHConfig,) -> paramiko.Channel:
1144+
def _get_proxy_channel(self, port: "typing.Optional[int]", ssh_config: _ssh_helpers.SSHConfig,) -> paramiko.Channel:
11471145
"""Get ssh proxy channel.
11481146
11491147
:param port: target port
@@ -1175,7 +1173,7 @@ def proxy_to(
11751173
verbose: bool = True,
11761174
ssh_config: _OptionalSSHConfigArgT = None,
11771175
ssh_auth_map: _OptionalSSHAuthMapT = None,
1178-
keepalive: "typing.Union[int, bool]" = 1,
1176+
keepalive: KeepAlivePeriodT = 1,
11791177
) -> "SSHClientBase":
11801178
"""Start new SSH connection using current as proxy.
11811179
@@ -1211,8 +1209,8 @@ def proxy_to(
12111209
12121210
.. versionadded:: 6.0.0
12131211
"""
1214-
if isinstance(ssh_config, HostsSSHConfigs):
1215-
parsed_ssh_config: HostsSSHConfigs = ssh_config
1212+
if isinstance(ssh_config, _ssh_helpers.HostsSSHConfigs):
1213+
parsed_ssh_config: _ssh_helpers.HostsSSHConfigs = ssh_config
12161214
else:
12171215
parsed_ssh_config = _ssh_helpers.parse_ssh_config(ssh_config, host)
12181216

@@ -1245,7 +1243,7 @@ def execute_through_host(
12451243
stdin: OptionalStdinT = None,
12461244
open_stdout: bool = True,
12471245
open_stderr: bool = True,
1248-
log_mask_re: "typing.Optional[str]" = None,
1246+
log_mask_re: LogMaskReT = None,
12491247
get_pty: bool = False,
12501248
width: int = 80,
12511249
height: int = 24,
@@ -1316,14 +1314,14 @@ def execute_together(
13161314
remotes: "typing.Iterable[SSHClientBase]",
13171315
command: CommandT,
13181316
timeout: OptionalTimeoutT = constants.DEFAULT_TIMEOUT,
1319-
expected: "typing.Iterable[ExitCodeT]" = (proc_enums.EXPECTED,),
1317+
expected: ExpectedExitCodesT = (proc_enums.EXPECTED,),
13201318
raise_on_err: bool = True,
13211319
*,
13221320
stdin: OptionalStdinT = None,
13231321
open_stdout: bool = True,
13241322
open_stderr: bool = True,
13251323
verbose: bool = False,
1326-
log_mask_re: "typing.Optional[str]" = None,
1324+
log_mask_re: LogMaskReT = None,
13271325
exception_class: "typing.Type[exceptions.ParallelCallProcessError]" = exceptions.ParallelCallProcessError,
13281326
**kwargs: typing.Any,
13291327
) -> "typing.Dict[typing.Tuple[str, int], exec_result.ExecResult]":
@@ -1521,9 +1519,7 @@ def islink(self, path: str) -> bool:
15211519
except IOError:
15221520
return False
15231521

1524-
def symlink(
1525-
self, source: "typing.Union[str, pathlib.PurePath]", dest: "typing.Union[str, pathlib.PurePath]"
1526-
) -> None:
1522+
def symlink(self, source: SupportPathT, dest: SupportPathT) -> None:
15271523
"""Produce symbolic link like `os.symlink`.
15281524
15291525
:param source: source path

exec_helpers/_ssh_helpers.py

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
# noinspection PyPackageRequirements
1313
import logwrap
1414

15+
SSHConfigDictLikeT = typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]
16+
SSHConfigsDictT = typing.Dict[str, SSHConfigDictLikeT]
17+
1518

1619
# Parse default SSHConfig if available
1720
SSH_CONFIG_FILE_SYSTEM = pathlib.Path("/etc/ssh/ssh_config")
@@ -199,10 +202,7 @@ def _parse_optional_bool(value: "typing.Optional[typing.Union[str, bool]]") -> "
199202

200203
@classmethod
201204
def from_ssh_config(
202-
cls,
203-
ssh_config: typing.Union[
204-
paramiko.config.SSHConfigDict, typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]
205-
],
205+
cls, ssh_config: typing.Union[paramiko.config.SSHConfigDict, SSHConfigDictLikeT],
206206
) -> "SSHConfig":
207207
"""Construct config from Paramiko parsed file.
208208
@@ -225,13 +225,13 @@ def from_ssh_config(
225225
)
226226

227227
@property
228-
def as_dict(self) -> "typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]":
228+
def as_dict(self) -> SSHConfigDictLikeT:
229229
"""Dictionary for rebuilding config.
230230
231231
:return: config as dictionary with only not None values
232232
:rtype: typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]
233233
"""
234-
result: "typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]" = {"hostname": self.hostname}
234+
result: SSHConfigDictLikeT = {"hostname": self.hostname}
235235
if self.port is not None:
236236
result["port"] = self.port
237237
if self.user is not None:
@@ -269,10 +269,7 @@ def overridden_by(self, ssh_config: "SSHConfig") -> "SSHConfig":
269269
)
270270

271271
def __eq__(
272-
self,
273-
other: typing.Union[
274-
"SSHConfig", typing.Dict[str, typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]], typing.Any
275-
],
272+
self, other: typing.Union["SSHConfig", SSHConfigDictLikeT, typing.Any],
276273
) -> "typing.Union[bool, type(NotImplemented)]": # type: ignore
277274
"""Equality check.
278275
@@ -415,9 +412,7 @@ def _parse_paramiko_ssh_config(conf: paramiko.SSHConfig, host: str) -> HostsSSHC
415412
return config
416413

417414

418-
def _parse_dict_ssh_config(
419-
conf: "typing.Dict[str, typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]]", host: str
420-
) -> HostsSSHConfigs:
415+
def _parse_dict_ssh_config(conf: SSHConfigsDictT, host: str) -> HostsSSHConfigs:
421416
"""Extract required data from pre-parsed ssh config for specific host to dictionary.
422417
423418
:param conf: pre-parsed dictionary
@@ -440,13 +435,7 @@ def _parse_dict_ssh_config(
440435

441436

442437
def parse_ssh_config(
443-
ssh_config: typing.Union[
444-
str,
445-
paramiko.SSHConfig,
446-
typing.Dict[str, typing.Dict[str, typing.Union[str, int, bool, typing.List[str]]]],
447-
None,
448-
],
449-
host: str,
438+
ssh_config: typing.Union[str, paramiko.SSHConfig, SSHConfigsDictT, None], host: str,
450439
) -> HostsSSHConfigs:
451440
"""Parse ssh config to get real connection parameters.
452441

0 commit comments

Comments
 (0)