Skip to content

Commit ee80368

Browse files
committed
Fix: unicode decode errors in exceptions
* fix fresh mypy * fix fresh futures checker
1 parent e1c8dcb commit ee80368

File tree

6 files changed

+57
-60
lines changed

6 files changed

+57
-60
lines changed

.pylintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ unsafe-load-any-extension=no
2828
# A comma-separated list of package or module names from where C extensions may
2929
# be loaded. Extensions are loading into the active Python interpreter and may
3030
# run arbitrary code
31-
extension-pkg-whitelist=
31+
extension-pkg-whitelist=lxml.etree
3232

3333
# Allow optimization of some AST trees. This will activate a peephole AST
3434
# optimizer, which will apply various small optimizations. For instance, it can

exec_helpers/_log_templates.py

Lines changed: 0 additions & 39 deletions
This file was deleted.

exec_helpers/_ssh_client_base.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
# Standard Library
2424
import abc
2525
import base64
26+
2627
# noinspection PyCompatibility
2728
import concurrent.futures
2829
import copy
@@ -43,7 +44,6 @@
4344
import threaded
4445

4546
# Exec-Helpers Implementation
46-
from exec_helpers import _log_templates
4747
from exec_helpers import api
4848
from exec_helpers import constants
4949
from exec_helpers import exceptions
@@ -159,7 +159,7 @@ def __call__( # type: ignore
159159
# If we have only cache reference and temporary getrefcount
160160
# reference: close connection before deletion
161161
cls.__cache[key].logger.debug("Closing as unused")
162-
cls.__cache[key].close() # type: ignore
162+
cls.__cache[key].close()
163163
del cls.__cache[key]
164164
# noinspection PyArgumentList
165165
ssh = super(_MemorizedSSH, cls).__call__(
@@ -185,15 +185,15 @@ def clear_cache(mcs): # type: (typing.Type[_MemorizedSSH]) -> None
185185
for ssh in mcs.__cache.values():
186186
if CPYTHON and sys.getrefcount(ssh) == n_count: # pragma: no cover
187187
ssh.logger.debug("Closing as unused")
188-
ssh.close() # type: ignore
188+
ssh.close()
189189
mcs.__cache = {}
190190

191191
@classmethod
192192
def close_connections(mcs): # type: (typing.Type[_MemorizedSSH]) -> None
193193
"""Close connections for selected or all cached records."""
194194
for ssh in mcs.__cache.values():
195195
if ssh.is_alive:
196-
ssh.close() # type: ignore
196+
ssh.close()
197197

198198

199199
class _SudoContext(object):
@@ -459,7 +459,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): # type: (typing.Any, typing.Any,
459459
.. versionchanged:: 1.2.1 disconnect enforced on close only not in keepalive mode
460460
"""
461461
if not self.__keepalive_mode:
462-
self.close() # type: ignore
462+
self.close()
463463
super(SSHClientBase, self).__exit__(exc_type, exc_val, exc_tb)
464464

465465
@property
@@ -498,7 +498,7 @@ def keepalive_mode(self, mode): # type: (bool) -> None
498498
def reconnect(self): # type: () -> None
499499
"""Reconnect SSH session."""
500500
with self.lock:
501-
self.close() # type: ignore
501+
self.close()
502502

503503
self.__ssh = paramiko.SSHClient()
504504
self.__ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -577,7 +577,8 @@ def execute_async(
577577
cmd_for_log = self._mask_command(cmd=command, log_mask_re=log_mask_re)
578578

579579
self.logger.log(
580-
level=logging.INFO if verbose else logging.DEBUG, msg=_log_templates.CMD_EXEC.format(cmd=cmd_for_log)
580+
level=logging.INFO if verbose else logging.DEBUG,
581+
msg="Executing command:\n{cmd!r}\n".format(cmd=cmd_for_log),
581582
)
582583

583584
chan = self._ssh.get_transport().open_session()
@@ -701,7 +702,7 @@ def poll_pipes(): # type: () -> None
701702
concurrent.futures.wait([future], 0.001)
702703
result.set_timestamp()
703704

704-
wait_err_msg = _log_templates.CMD_WAIT_ERROR.format(result=result, timeout=timeout)
705+
wait_err_msg = exceptions.make_timeout_error_message(result=result, timeout=timeout) # type: ignore
705706
self.logger.debug(wait_err_msg)
706707
raise exceptions.ExecHelperTimeoutError(result=result, timeout=timeout) # type: ignore
707708

@@ -743,7 +744,8 @@ def execute_through_host(
743744
"""
744745
cmd_for_log = self._mask_command(cmd=command, log_mask_re=kwargs.get("log_mask_re", None))
745746
self.logger.log(
746-
level=logging.INFO if verbose else logging.DEBUG, msg=_log_templates.CMD_EXEC.format(cmd=cmd_for_log)
747+
level=logging.INFO if verbose else logging.DEBUG,
748+
msg="Executing command:\n{cmd!r}\n".format(cmd=cmd_for_log),
747749
)
748750

749751
if auth is None:

exec_helpers/exceptions.py

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import typing
2323

2424
# Exec-Helpers Implementation
25-
from exec_helpers import _log_templates
2625
from exec_helpers import proc_enums
2726

2827
if typing.TYPE_CHECKING: # pragma: no cover
@@ -110,10 +109,36 @@ def __init__(self, result, timeout): # type: (exec_result.ExecResult, typing.Un
110109
:param timeout: timeout for command
111110
:type timeout: typing.Union[int, float]
112111
"""
113-
message = _log_templates.CMD_KILL_ERROR.format(result=result, timeout=timeout)
112+
stdout_brief = result.stdout_brief.encode(encoding="utf-8", errors="backslashreplace").decode("utf-8")
113+
stderr_brief = result.stderr_brief.encode(encoding="utf-8", errors="backslashreplace").decode("utf-8")
114+
message = (
115+
"Wait for {result.cmd!r} during {timeout!s}s: no return code and no response on SIGTERM + SIGKILL signals!"
116+
"\n"
117+
"\tSTDOUT:\n"
118+
"{stdout_brief}\n"
119+
"\tSTDERR:\n"
120+
"{stderr_brief}".format(
121+
result=result, timeout=timeout, stdout_brief=stdout_brief, stderr_brief=stderr_brief
122+
)
123+
)
114124
super(ExecHelperNoKillError, self).__init__(message, result=result, timeout=timeout)
115125

116126

127+
def make_timeout_error_message(
128+
result, timeout
129+
): # type: (exec_result.ExecResult, typing.Union[int, float]) -> typing.Text
130+
"""Make timeout failed message."""
131+
stdout_brief = result.stdout_brief.encode(encoding="utf-8", errors="backslashreplace").decode("utf-8")
132+
stderr_brief = result.stderr_brief.encode(encoding="utf-8", errors="backslashreplace").decode("utf-8")
133+
return (
134+
"Wait for {result.cmd!r} during {timeout!s}s: no return code!\n"
135+
"\tSTDOUT:\n"
136+
"{stdout_brief}\n"
137+
"\tSTDERR:\n"
138+
"{stderr_brief}".format(result=result, timeout=timeout, stdout_brief=stdout_brief, stderr_brief=stderr_brief)
139+
)
140+
141+
117142
class ExecHelperTimeoutError(ExecHelperTimeoutProcessError):
118143
"""Execution timeout.
119144
@@ -131,8 +156,9 @@ def __init__(self, result, timeout): # type: (exec_result.ExecResult, typing.Un
131156
:param timeout: timeout for command
132157
:type timeout: typing.Union[int, float]
133158
"""
134-
message = _log_templates.CMD_WAIT_ERROR.format(result=result, timeout=timeout)
135-
super(ExecHelperTimeoutError, self).__init__(message, result=result, timeout=timeout)
159+
super(ExecHelperTimeoutError, self).__init__(
160+
make_timeout_error_message(result=result, timeout=timeout), result=result, timeout=timeout
161+
)
136162

137163

138164
class CalledProcessError(ExecCalledProcessError):
@@ -157,12 +183,17 @@ def __init__(
157183
"""
158184
self.result = result
159185
self.expected = proc_enums.exit_codes_to_enums(expected)
186+
stdout_brief = result.stdout_brief.encode(encoding="utf-8", errors="backslashreplace").decode("utf-8")
187+
stderr_brief = result.stderr_brief.encode(encoding="utf-8", errors="backslashreplace").decode("utf-8")
160188
message = (
161189
"Command {result.cmd!r} returned exit code {result.exit_code} "
162190
"while expected {expected}\n"
163191
"\tSTDOUT:\n"
164-
"{result.stdout_brief}\n"
165-
"\tSTDERR:\n{result.stderr_brief}".format(result=self.result, expected=self.expected)
192+
"{stdout_brief}\n"
193+
"\tSTDERR:\n"
194+
"{stderr_brief}".format(
195+
result=self.result, expected=self.expected, stdout_brief=stdout_brief, stderr_brief=stderr_brief
196+
)
166197
)
167198
super(CalledProcessError, self).__init__(message)
168199

exec_helpers/subprocess_runner.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import threaded
3535

3636
# Exec-Helpers Implementation
37-
from exec_helpers import _log_templates
3837
from exec_helpers import _subprocess_helpers
3938
from exec_helpers import api
4039
from exec_helpers import exceptions
@@ -50,9 +49,9 @@ class SubprocessExecuteAsyncResult(api.ExecuteAsyncResult):
5049
"""Override original NamedTuple with proper typing."""
5150

5251
@property
53-
def interface(self): # type: () -> subprocess.Popen
52+
def interface(self): # type: () -> subprocess.Popen[typing.Union[str, typing.Text]]
5453
"""Override original NamedTuple with proper typing."""
55-
return super(SubprocessExecuteAsyncResult, self).interface
54+
return super(SubprocessExecuteAsyncResult, self).interface # type: ignore
5655

5756

5857
class Subprocess(api.ExecHelper):
@@ -165,7 +164,7 @@ def close_streams(): # type: () -> None
165164
result.set_timestamp()
166165
close_streams()
167166

168-
wait_err_msg = _log_templates.CMD_WAIT_ERROR.format(result=result, timeout=timeout)
167+
wait_err_msg = exceptions.make_timeout_error_message(result=result, timeout=timeout)
169168
self.logger.debug(wait_err_msg)
170169
raise exceptions.ExecHelperTimeoutError(result=result, timeout=timeout)
171170

@@ -217,7 +216,8 @@ def execute_async(
217216
cmd_for_log = self._mask_command(cmd=command, log_mask_re=log_mask_re)
218217

219218
self.logger.log(
220-
level=logging.INFO if verbose else logging.DEBUG, msg=_log_templates.CMD_EXEC.format(cmd=cmd_for_log)
219+
level=logging.INFO if verbose else logging.DEBUG,
220+
msg="Executing command:\n{cmd!r}\n".format(cmd=cmd_for_log),
221221
)
222222

223223
started = datetime.datetime.utcnow()

tox.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ deps =
5353
commands = pip install ./ -vvv -U
5454

5555
[testenv:pylint]
56+
basepython=python2
5657
usedevelop = False
5758
deps =
5859
pylint<2
@@ -101,6 +102,8 @@ ignore =
101102
FI16
102103
# __future__ import "generators" missing
103104
FI17
105+
#__future__ import "annotations" missing
106+
FI18
104107
# line break before binary operator
105108
W503
106109
# First line should be in imperative mood; try rephrasing

0 commit comments

Comments
 (0)