Skip to content

Commit 46ae6b4

Browse files
committed
Allow direct call of helpers: shortcut to execute
(cherry picked from commit 3ab7700) Signed-off-by: Alexey Stepanov <penguinolog@gmail.com>
1 parent 8e79fed commit 46ae6b4

File tree

7 files changed

+101
-2
lines changed

7 files changed

+101
-2
lines changed

README.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ This methods are almost the same for `SSHCleint` and `Subprocess`, except specif
162162
exception_class=CalledProcessError, # typing.Type[CalledProcessError]
163163
)
164164
165+
.. code-block:: python
166+
167+
result = helper( # Lazy way: instances are callable and uses `execute`.
168+
command, # type: str
169+
verbose=False, # type: bool
170+
timeout=1 * 60 * 60, # type: typing.Union[int, float, None]
171+
**kwargs
172+
)
173+
165174
If no STDOUT or STDERR required, it is possible to disable this FIFO pipes via `**kwargs` with flags `open_stdout=False` and `open_stderr=False`.
166175

167176
The next command level uses lower level and kwargs are forwarded, so expected exit codes are forwarded from `check_stderr`.

doc/source/SSHClient.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,21 @@ API: SSHClient and SSHAuth.
167167

168168
.. versionchanged:: 1.2.0 default timeout 1 hour
169169

170+
.. py:method:: __call__(command, verbose=False, timeout=1*60*60, **kwargs)
171+
172+
Execute command and wait for return code.
173+
174+
:param command: Command for execution
175+
:type command: ``str``
176+
:param verbose: Produce log.info records for command call and output
177+
:type verbose: ``bool``
178+
:param timeout: Timeout for command execution.
179+
:type timeout: ``typing.Union[int, float, None]``
180+
:rtype: ExecResult
181+
:raises ExecHelperTimeoutError: Timeout exceeded
182+
183+
.. versionadded:: 2.9.4
184+
170185
.. py:method:: check_call(command, verbose=False, timeout=1*60*60, error_info=None, expected=None, raise_on_err=True, *, exception_class=CalledProcessError, **kwargs)
171186
172187
Execute command and check for return code.

doc/source/Subprocess.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ API: Subprocess
9090
.. versionchanged:: 1.2.0 default timeout 1 hour
9191
.. versionchanged:: 1.2.0 stdin data
9292

93+
.. py:method:: __call__(command, verbose=False, timeout=1*60*60, **kwargs)
94+
95+
Execute command and wait for return code.
96+
97+
:param command: Command for execution
98+
:type command: ``str``
99+
:param verbose: Produce log.info records for command call and output
100+
:type verbose: ``bool``
101+
:param timeout: Timeout for command execution.
102+
:type timeout: ``typing.Union[int, float, None]``
103+
:rtype: ExecResult
104+
:raises ExecHelperTimeoutError: Timeout exceeded
105+
106+
.. note:: stdin channel is closed after the input processing
107+
.. versionadded:: 2.9.4
108+
93109
.. py:method:: check_call(command, verbose=False, timeout=1*60*60, error_info=None, expected=None, raise_on_err=True, *, exception_class=CalledProcessError, **kwargs)
94110
95111
Execute command and check for return code.

exec_helpers/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@
5151
"ExecResult",
5252
)
5353

54-
try:
54+
try: # pragma: no cover
5555
__version__ = pkg_resources.get_distribution(__name__).version
56-
except pkg_resources.DistributionNotFound:
56+
except pkg_resources.DistributionNotFound: # pragma: no cover
5757
# package is not installed, try to get from SCM
5858
try:
5959
# noinspection PyPackageRequirements,PyUnresolvedReferences

exec_helpers/api.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,31 @@ def execute(
250250
self.logger.log(level=logging.INFO if verbose else logging.DEBUG, msg=message) # type: ignore
251251
return result
252252

253+
def __call__(
254+
self,
255+
command: str,
256+
verbose: bool = False,
257+
timeout: typing.Union[int, float, None] = constants.DEFAULT_TIMEOUT,
258+
**kwargs: typing.Any
259+
) -> exec_result.ExecResult:
260+
"""Execute command and wait for return code.
261+
262+
:param command: Command for execution
263+
:type command: str
264+
:param verbose: Produce log.info records for command call and output
265+
:type verbose: bool
266+
:param timeout: Timeout for command execution.
267+
:type timeout: typing.Union[int, float, None]
268+
:param kwargs: additional parameters for call.
269+
:type kwargs: typing.Any
270+
:return: Execution result
271+
:rtype: ExecResult
272+
:raises ExecHelperTimeoutError: Timeout exceeded
273+
274+
.. versionadded:: 2.9.4
275+
"""
276+
return self.execute(command=command, verbose=verbose, timeout=timeout, **kwargs)
277+
253278
def check_call(
254279
self,
255280
command: str,

test/test_ssh_client_execute.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,3 +506,24 @@ def test_010_execute_together_expected(ssh, ssh2, execute_async, exec_result, ru
506506
)
507507
)
508508
assert results == {(host, port): exec_result, (host2, port): exec_result}
509+
510+
511+
def test_011_call(ssh, ssh_transport_channel, exec_result, run_parameters) -> None:
512+
kwargs = {}
513+
if "get_pty" in run_parameters:
514+
kwargs["get_pty"] = run_parameters["get_pty"]
515+
if "width" in run_parameters:
516+
kwargs["width"] = run_parameters["width"]
517+
if "height" in run_parameters:
518+
kwargs["height"] = run_parameters["height"]
519+
520+
res = ssh(
521+
command,
522+
stdin=run_parameters["stdin"],
523+
open_stdout=run_parameters["open_stdout"],
524+
open_stderr=run_parameters["open_stderr"],
525+
**kwargs
526+
)
527+
assert isinstance(res, exec_helpers.ExecResult)
528+
assert res == exec_result
529+
ssh_transport_channel.assert_has_calls((mock.call.status_event.is_set(),))

test/test_subprocess.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,16 @@ def test_008_check_stderr_no_raise(execute, exec_result, logger) -> None:
317317
runner.check_stderr(command, stdin=exec_result.stdin, expected=[exec_result.exit_code], raise_on_err=False)
318318
== exec_result
319319
)
320+
321+
322+
def test_009_call(popen, logger, exec_result, run_parameters) -> None:
323+
runner = exec_helpers.Subprocess()
324+
res = runner(
325+
command,
326+
stdin=run_parameters["stdin"],
327+
open_stdout=run_parameters["open_stdout"],
328+
open_stderr=run_parameters["open_stderr"],
329+
)
330+
assert isinstance(res, exec_helpers.ExecResult)
331+
assert res == exec_result
332+
popen().wait.assert_called_once_with(timeout=default_timeout)

0 commit comments

Comments
 (0)