dycw-utilities 0.174.2__tar.gz → 0.174.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/PKG-INFO +1 -1
  2. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/pyproject.toml +2 -2
  3. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/__init__.py +1 -1
  4. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/subprocess.py +70 -78
  5. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/README.md +0 -0
  6. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/aeventkit.py +0 -0
  7. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/altair.py +0 -0
  8. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/asyncio.py +0 -0
  9. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/atomicwrites.py +0 -0
  10. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/atools.py +0 -0
  11. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/cachetools.py +0 -0
  12. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/click.py +0 -0
  13. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/concurrent.py +0 -0
  14. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/contextlib.py +0 -0
  15. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/contextvars.py +0 -0
  16. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/cryptography.py +0 -0
  17. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/cvxpy.py +0 -0
  18. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/dataclasses.py +0 -0
  19. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/docker.py +0 -0
  20. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/enum.py +0 -0
  21. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/errors.py +0 -0
  22. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/fastapi.py +0 -0
  23. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/fpdf2.py +0 -0
  24. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/functions.py +0 -0
  25. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/functools.py +0 -0
  26. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/getpass.py +0 -0
  27. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/git.py +0 -0
  28. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/grp.py +0 -0
  29. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/gzip.py +0 -0
  30. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/hashlib.py +0 -0
  31. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/http.py +0 -0
  32. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/hypothesis.py +0 -0
  33. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/importlib.py +0 -0
  34. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/inflect.py +0 -0
  35. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/ipython.py +0 -0
  36. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/iterables.py +0 -0
  37. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/jinja2.py +0 -0
  38. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/json.py +0 -0
  39. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/jupyter.py +0 -0
  40. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/libcst.py +0 -0
  41. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/lightweight_charts.py +0 -0
  42. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/logging.py +0 -0
  43. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/math.py +0 -0
  44. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/memory_profiler.py +0 -0
  45. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/modules.py +0 -0
  46. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/more_itertools.py +0 -0
  47. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/numpy.py +0 -0
  48. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/operator.py +0 -0
  49. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/optuna.py +0 -0
  50. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/orjson.py +0 -0
  51. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/os.py +0 -0
  52. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/parse.py +0 -0
  53. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pathlib.py +0 -0
  54. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pickle.py +0 -0
  55. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/platform.py +0 -0
  56. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/polars.py +0 -0
  57. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/polars_ols.py +0 -0
  58. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/postgres.py +0 -0
  59. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pottery.py +0 -0
  60. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pqdm.py +0 -0
  61. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/psutil.py +0 -0
  62. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pwd.py +0 -0
  63. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/py.typed +0 -0
  64. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pydantic.py +0 -0
  65. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pydantic_settings.py +0 -0
  66. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pydantic_settings_sops.py +0 -0
  67. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pyinstrument.py +0 -0
  68. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pytest.py +0 -0
  69. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pytest_plugins/__init__.py +0 -0
  70. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
  71. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
  72. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/pytest_regressions.py +0 -0
  73. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/random.py +0 -0
  74. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/re.py +0 -0
  75. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/redis.py +0 -0
  76. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/reprlib.py +0 -0
  77. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/scipy.py +0 -0
  78. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/sentinel.py +0 -0
  79. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/shelve.py +0 -0
  80. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/shutil.py +0 -0
  81. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/slack_sdk.py +0 -0
  82. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/socket.py +0 -0
  83. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/sqlalchemy.py +0 -0
  84. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/sqlalchemy_polars.py +0 -0
  85. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/statsmodels.py +0 -0
  86. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/string.py +0 -0
  87. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/tempfile.py +0 -0
  88. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/testbook.py +0 -0
  89. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/text.py +0 -0
  90. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/threading.py +0 -0
  91. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/timer.py +0 -0
  92. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/traceback.py +0 -0
  93. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/types.py +0 -0
  94. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/typing.py +0 -0
  95. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/tzdata.py +0 -0
  96. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/tzlocal.py +0 -0
  97. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/uuid.py +0 -0
  98. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/version.py +0 -0
  99. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/warnings.py +0 -0
  100. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/whenever.py +0 -0
  101. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/zipfile.py +0 -0
  102. {dycw_utilities-0.174.2 → dycw_utilities-0.174.3}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dycw-utilities
3
- Version: 0.174.2
3
+ Version: 0.174.3
4
4
  Author: Derek Wan
5
5
  Author-email: Derek Wan <d.wan@icloud.com>
6
6
  Requires-Dist: atomicwrites>=1.4.1,<1.5
@@ -101,7 +101,7 @@
101
101
  name = "dycw-utilities"
102
102
  readme = "README.md"
103
103
  requires-python = ">= 3.12"
104
- version = "0.174.2"
104
+ version = "0.174.3"
105
105
 
106
106
  [project.entry-points.pytest11]
107
107
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -135,7 +135,7 @@
135
135
  # bump-my-version
136
136
  [tool.bumpversion]
137
137
  allow_dirty = true
138
- current_version = "0.174.2"
138
+ current_version = "0.174.3"
139
139
 
140
140
  [[tool.bumpversion.files]]
141
141
  filename = "src/utilities/__init__.py"
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.174.2"
3
+ __version__ = "0.174.3"
@@ -13,15 +13,16 @@ from typing import IO, TYPE_CHECKING, Literal, assert_never, overload
13
13
  from utilities.errors import ImpossibleCaseError
14
14
  from utilities.logging import to_logger
15
15
  from utilities.text import strip_and_dedent
16
+ from utilities.types import Delta
17
+ from utilities.whenever import to_seconds
16
18
 
17
19
  if TYPE_CHECKING:
18
20
  from collections.abc import Iterator
19
21
 
20
- from whenever import TimeDelta
21
-
22
22
  from utilities.types import LoggerLike, PathLike, StrMapping, StrStrMapping
23
23
 
24
24
 
25
+ type _Retry = tuple[int, Delta | None]
25
26
  _HOST_KEY_ALGORITHMS = ["ssh-ed25519"]
26
27
  BASH_LC = ["bash", "-lc"]
27
28
  BASH_LS = ["bash", "-ls"]
@@ -82,6 +83,7 @@ def run(
82
83
  return_: Literal[True],
83
84
  return_stdout: bool = False,
84
85
  return_stderr: bool = False,
86
+ retry: _Retry | None = None,
85
87
  logger: LoggerLike | None = None,
86
88
  ) -> str: ...
87
89
  @overload
@@ -101,6 +103,7 @@ def run(
101
103
  return_: bool = False,
102
104
  return_stdout: Literal[True],
103
105
  return_stderr: bool = False,
106
+ retry: _Retry | None = None,
104
107
  logger: LoggerLike | None = None,
105
108
  ) -> str: ...
106
109
  @overload
@@ -120,6 +123,7 @@ def run(
120
123
  return_: bool = False,
121
124
  return_stdout: bool = False,
122
125
  return_stderr: Literal[True],
126
+ retry: _Retry | None = None,
123
127
  logger: LoggerLike | None = None,
124
128
  ) -> str: ...
125
129
  @overload
@@ -139,6 +143,7 @@ def run(
139
143
  return_: Literal[False] = False,
140
144
  return_stdout: Literal[False] = False,
141
145
  return_stderr: Literal[False] = False,
146
+ retry: _Retry | None = None,
142
147
  logger: LoggerLike | None = None,
143
148
  ) -> None: ...
144
149
  @overload
@@ -158,6 +163,7 @@ def run(
158
163
  return_: bool = False,
159
164
  return_stdout: bool = False,
160
165
  return_stderr: bool = False,
166
+ retry: _Retry | None = None,
161
167
  logger: LoggerLike | None = None,
162
168
  ) -> str | None: ...
163
169
  def run(
@@ -176,10 +182,11 @@ def run(
176
182
  return_: bool = False,
177
183
  return_stdout: bool = False,
178
184
  return_stderr: bool = False,
185
+ retry: _Retry | None = None,
179
186
  logger: LoggerLike | None = None,
180
187
  ) -> str | None:
181
188
  args: list[str] = []
182
- if user is not None:
189
+ if user is not None: # pragma: no cover
183
190
  args.extend(["su", "-", str(user)])
184
191
  args.extend([cmd, *cmds_or_args])
185
192
  buffer = StringIO()
@@ -211,8 +218,8 @@ def run(
211
218
  if proc.stderr is None: # pragma: no cover
212
219
  raise ImpossibleCaseError(case=[f"{proc.stderr=}"])
213
220
  with (
214
- _yield_write(proc.stdout, "proc.stdout", *stdout_outputs),
215
- _yield_write(proc.stderr, "proc.stderr", *stderr_outputs),
221
+ _yield_write(proc.stdout, *stdout_outputs),
222
+ _yield_write(proc.stderr, *stderr_outputs),
216
223
  ):
217
224
  if input is not None:
218
225
  _ = proc.stdin.write(input)
@@ -232,6 +239,10 @@ def run(
232
239
  case 0, False, False:
233
240
  return None
234
241
  case _, _, _:
242
+ if retry is None:
243
+ attempts = delta = None
244
+ else:
245
+ attempts, delta = retry
235
246
  _ = stdout.seek(0)
236
247
  stdout_text = stdout.read()
237
248
  _ = stderr.seek(0)
@@ -246,24 +257,52 @@ def run(
246
257
  - shell = {shell}
247
258
  - cwd = {cwd}
248
259
  - env = {env}
249
- - input = {input}
250
260
 
261
+ -- stdin ----------------------------------------------------------------------
262
+ {"" if input is None else input}-------------------------------------------------------------------------------
251
263
  -- stdout ---------------------------------------------------------------------
252
264
  {stdout_text}-------------------------------------------------------------------------------
253
265
  -- stderr ---------------------------------------------------------------------
254
266
  {stderr_text}-------------------------------------------------------------------------------
255
267
  """)
268
+ if (attempts is not None) and (attempts >= 1):
269
+ if delta is None:
270
+ msg = f"{msg}\n\nRetrying {attempts} more time(s)..."
271
+ else:
272
+ msg = f"{msg}\n\nRetrying {attempts} more time(s) after {delta}..."
256
273
  to_logger(logger).error(msg)
257
- raise CalledProcessError(
274
+ error = CalledProcessError(
258
275
  return_code, args, output=stdout_text, stderr=stderr_text
259
276
  )
277
+ if (attempts is None) or (attempts <= 0):
278
+ raise error
279
+ if delta is not None:
280
+ sleep(to_seconds(delta))
281
+ return run(
282
+ cmd,
283
+ *cmds_or_args,
284
+ user=user,
285
+ executable=executable,
286
+ shell=shell,
287
+ cwd=cwd,
288
+ env=env,
289
+ input=input,
290
+ print=print,
291
+ print_stdout=print_stdout,
292
+ print_stderr=print_stderr,
293
+ return_=return_,
294
+ return_stdout=return_stdout,
295
+ return_stderr=return_stderr,
296
+ retry=(attempts - 1, delta),
297
+ logger=logger,
298
+ )
260
299
  case never:
261
300
  assert_never(never)
262
301
 
263
302
 
264
303
  @contextmanager
265
- def _yield_write(input_: IO[str], desc: str, /, *outputs: IO[str]) -> Iterator[None]:
266
- thread = Thread(target=_run_target, args=(input_, desc, *outputs), daemon=True)
304
+ def _yield_write(input_: IO[str], /, *outputs: IO[str]) -> Iterator[None]:
305
+ thread = Thread(target=_run_target, args=(input_, *outputs), daemon=True)
267
306
  thread.start()
268
307
  try:
269
308
  yield
@@ -271,14 +310,10 @@ def _yield_write(input_: IO[str], desc: str, /, *outputs: IO[str]) -> Iterator[N
271
310
  thread.join()
272
311
 
273
312
 
274
- def _run_target(input_: IO[str], desc: str, /, *outputs: IO[str]) -> None:
275
- try:
276
- with input_:
277
- for text in iter(input_.readline, ""):
278
- _write_to_streams(text, *outputs)
279
- except ValueError:
280
- _ = sys.stderr.write(f"Failed to write to {desc!r}...")
281
- raise
313
+ def _run_target(input_: IO[str], /, *outputs: IO[str]) -> None:
314
+ with input_:
315
+ for text in iter(input_.readline, ""):
316
+ _write_to_streams(text, *outputs)
282
317
 
283
318
 
284
319
  def _write_to_streams(text: str, /, *outputs: IO[str]) -> None:
@@ -302,8 +337,8 @@ def ssh(
302
337
  return_: Literal[True],
303
338
  return_stdout: bool = False,
304
339
  return_stderr: bool = False,
340
+ retry: _Retry | None = None,
305
341
  logger: LoggerLike | None = None,
306
- retry: tuple[int, TimeDelta] | None = None,
307
342
  ) -> str: ...
308
343
  @overload
309
344
  def ssh(
@@ -321,8 +356,8 @@ def ssh(
321
356
  return_: bool = False,
322
357
  return_stdout: Literal[True],
323
358
  return_stderr: bool = False,
359
+ retry: _Retry | None = None,
324
360
  logger: LoggerLike | None = None,
325
- retry: tuple[int, TimeDelta] | None = None,
326
361
  ) -> str: ...
327
362
  @overload
328
363
  def ssh(
@@ -340,8 +375,8 @@ def ssh(
340
375
  return_: bool = False,
341
376
  return_stdout: bool = False,
342
377
  return_stderr: Literal[True],
378
+ retry: _Retry | None = None,
343
379
  logger: LoggerLike | None = None,
344
- retry: tuple[int, TimeDelta] | None = None,
345
380
  ) -> str: ...
346
381
  @overload
347
382
  def ssh(
@@ -359,8 +394,8 @@ def ssh(
359
394
  return_: Literal[False] = False,
360
395
  return_stdout: Literal[False] = False,
361
396
  return_stderr: Literal[False] = False,
397
+ retry: _Retry | None = None,
362
398
  logger: LoggerLike | None = None,
363
- retry: tuple[int, TimeDelta] | None = None,
364
399
  ) -> None: ...
365
400
  @overload
366
401
  def ssh(
@@ -378,8 +413,8 @@ def ssh(
378
413
  return_: bool = False,
379
414
  return_stdout: bool = False,
380
415
  return_stderr: bool = False,
416
+ retry: _Retry | None = None,
381
417
  logger: LoggerLike | None = None,
382
- retry: tuple[int, TimeDelta] | None = None,
383
418
  ) -> str | None: ...
384
419
  def ssh(
385
420
  user: str,
@@ -396,8 +431,8 @@ def ssh(
396
431
  return_: bool = False,
397
432
  return_stdout: bool = False,
398
433
  return_stderr: bool = False,
434
+ retry: _Retry | None = None,
399
435
  logger: LoggerLike | None = None,
400
- retry: tuple[int, TimeDelta] | None = None,
401
436
  ) -> str | None:
402
437
  cmd_and_args = ssh_cmd( # skipif-ci
403
438
  user,
@@ -407,61 +442,18 @@ def ssh(
407
442
  host_key_algorithms=host_key_algorithms,
408
443
  strict_host_key_checking=strict_host_key_checking,
409
444
  )
410
- try: # skipif-ci
411
- return run(
412
- *cmd_and_args,
413
- input=input,
414
- print=print,
415
- print_stdout=print_stdout,
416
- print_stderr=print_stderr,
417
- return_=return_,
418
- return_stdout=return_stdout,
419
- return_stderr=return_stderr,
420
- logger=logger,
421
- )
422
- except CalledProcessError as error: # skipif-ci
423
- if retry is None:
424
- raise
425
- attempts, delta = retry
426
- if attempts <= 0:
427
- raise
428
- if logger is not None:
429
- msg = strip_and_dedent(f"""
430
- 'ssh' failed with:
431
- - user = {user}
432
- - hostname = {hostname}
433
- - cmd_and_cmds_or_args = {cmd_and_cmds_or_args}
434
- - batch_mode = {batch_mode}
435
- - host_key_algorithms = {host_key_algorithms}
436
- - strict_host_key_checking = {strict_host_key_checking}
437
- - input = {input}
438
-
439
- -- stdout ---------------------------------------------------------------------
440
- {error.stdout}-------------------------------------------------------------------------------
441
- -- stderr ---------------------------------------------------------------------
442
- {error.stderr}-------------------------------------------------------------------------------
443
-
444
- Retrying {attempts} more time(s) after {delta}...
445
- """)
446
- to_logger(logger).error(msg)
447
- sleep(delta.in_seconds())
448
- return ssh(
449
- user,
450
- hostname,
451
- *cmd_and_cmds_or_args,
452
- batch_mode=batch_mode,
453
- host_key_algorithms=host_key_algorithms,
454
- strict_host_key_checking=strict_host_key_checking,
455
- input=input,
456
- print=print,
457
- print_stdout=print_stdout,
458
- print_stderr=print_stderr,
459
- return_=return_,
460
- return_stdout=return_stdout,
461
- return_stderr=return_stderr,
462
- logger=logger,
463
- retry=(attempts - 1, delta),
464
- )
445
+ return run( # skipif-ci
446
+ *cmd_and_args,
447
+ input=input,
448
+ print=print,
449
+ print_stdout=print_stdout,
450
+ print_stderr=print_stderr,
451
+ return_=return_,
452
+ return_stdout=return_stdout,
453
+ return_stderr=return_stderr,
454
+ retry=retry,
455
+ logger=logger,
456
+ )
465
457
 
466
458
 
467
459
  def ssh_cmd(