dycw-utilities 0.174.1__py3-none-any.whl → 0.174.2__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dycw-utilities
3
- Version: 0.174.1
3
+ Version: 0.174.2
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
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=tLO7x-PFRNnbxnNKusLHsRm5KouG5gC6-6CMhoP9aSQ,60
1
+ utilities/__init__.py,sha256=eQ7qF5gZG8QDtJhV_65EUYKkQ_P0qw2ExXVGxnEVcaU,60
2
2
  utilities/aeventkit.py,sha256=OmDBhYGgbsKrB7cdC5FFpJHUatX9O76eTeKVVTksp2Y,12673
3
3
  utilities/altair.py,sha256=rUK99g9x6CYDDfiZrf-aTx5fSRbL1Q8ctgKORowzXHg,9060
4
4
  utilities/asyncio.py,sha256=aJySVxBY0gqsIYnoNmH7-1r8djKuf4vSsU69VCD08t8,16772
@@ -80,7 +80,7 @@ utilities/sqlalchemy.py,sha256=HQYpd7LFxdTF5WYVWYtCJeEBI71EJm7ytvCGyAH9B-U,37163
80
80
  utilities/sqlalchemy_polars.py,sha256=JCGhB37raSR7fqeWV5dTsciRTMVzIdVT9YSqKT0piT0,13370
81
81
  utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
82
82
  utilities/string.py,sha256=shmBK87zZwzGyixuNuXCiUbqzfeZ9xlrFwz6JTaRvDk,582
83
- utilities/subprocess.py,sha256=8kGrQLnPnlbdXeWE7OPk9Pih2KBNyjBKbntdiloQVrY,13066
83
+ utilities/subprocess.py,sha256=t_kbBQ7YG9LMBBpkqNcOWuhq6kwaLJBSlWRIn7rkWwY,15587
84
84
  utilities/tempfile.py,sha256=Lx6qa16lL1XVH6WdmD_G9vlN6gLI8nrIurxmsFkPKvg,3022
85
85
  utilities/testbook.py,sha256=j1KmaVbrX9VrbeMgtPh5gk55myAsn3dyRUn7jGbPbRk,1294
86
86
  utilities/text.py,sha256=7SvwcSR2l_5cOrm1samGnR4C-ZI6qyFLHLzSpO1zeHQ,13958
@@ -97,7 +97,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
97
97
  utilities/whenever.py,sha256=F4ek0-OBWxHYrZdmoZt76N2RnNyKY5KrEHt7rqO4AQE,60183
98
98
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
99
99
  utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
100
- dycw_utilities-0.174.1.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
101
- dycw_utilities-0.174.1.dist-info/entry_points.txt,sha256=ykGI1ArwOPHqm2g5Cqh3ENdMxEej_a_FcOUov5EM5Oc,155
102
- dycw_utilities-0.174.1.dist-info/METADATA,sha256=olH83qMZVFRCSDboBVmfiiCV1d4hKdtVyvCFi6s1Gp0,1709
103
- dycw_utilities-0.174.1.dist-info/RECORD,,
100
+ dycw_utilities-0.174.2.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
101
+ dycw_utilities-0.174.2.dist-info/entry_points.txt,sha256=ykGI1ArwOPHqm2g5Cqh3ENdMxEej_a_FcOUov5EM5Oc,155
102
+ dycw_utilities-0.174.2.dist-info/METADATA,sha256=e3WUzrZEJzZU0tF6f8M2ZCOT6hyXaCaNo6MBp_K88pI,1709
103
+ dycw_utilities-0.174.2.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.174.1"
3
+ __version__ = "0.174.2"
utilities/subprocess.py CHANGED
@@ -7,6 +7,7 @@ from pathlib import Path
7
7
  from string import Template
8
8
  from subprocess import PIPE, CalledProcessError, Popen
9
9
  from threading import Thread
10
+ from time import sleep
10
11
  from typing import IO, TYPE_CHECKING, Literal, assert_never, overload
11
12
 
12
13
  from utilities.errors import ImpossibleCaseError
@@ -16,6 +17,8 @@ from utilities.text import strip_and_dedent
16
17
  if TYPE_CHECKING:
17
18
  from collections.abc import Iterator
18
19
 
20
+ from whenever import TimeDelta
21
+
19
22
  from utilities.types import LoggerLike, PathLike, StrMapping, StrStrMapping
20
23
 
21
24
 
@@ -300,6 +303,7 @@ def ssh(
300
303
  return_stdout: bool = False,
301
304
  return_stderr: bool = False,
302
305
  logger: LoggerLike | None = None,
306
+ retry: tuple[int, TimeDelta] | None = None,
303
307
  ) -> str: ...
304
308
  @overload
305
309
  def ssh(
@@ -318,6 +322,7 @@ def ssh(
318
322
  return_stdout: Literal[True],
319
323
  return_stderr: bool = False,
320
324
  logger: LoggerLike | None = None,
325
+ retry: tuple[int, TimeDelta] | None = None,
321
326
  ) -> str: ...
322
327
  @overload
323
328
  def ssh(
@@ -336,6 +341,7 @@ def ssh(
336
341
  return_stdout: bool = False,
337
342
  return_stderr: Literal[True],
338
343
  logger: LoggerLike | None = None,
344
+ retry: tuple[int, TimeDelta] | None = None,
339
345
  ) -> str: ...
340
346
  @overload
341
347
  def ssh(
@@ -354,7 +360,27 @@ def ssh(
354
360
  return_stdout: Literal[False] = False,
355
361
  return_stderr: Literal[False] = False,
356
362
  logger: LoggerLike | None = None,
363
+ retry: tuple[int, TimeDelta] | None = None,
357
364
  ) -> None: ...
365
+ @overload
366
+ def ssh(
367
+ user: str,
368
+ hostname: str,
369
+ /,
370
+ *cmd_and_cmds_or_args: str,
371
+ batch_mode: bool = True,
372
+ host_key_algorithms: list[str] = _HOST_KEY_ALGORITHMS,
373
+ strict_host_key_checking: bool = True,
374
+ input: str | None = None,
375
+ print: bool = False,
376
+ print_stdout: bool = False,
377
+ print_stderr: bool = False,
378
+ return_: bool = False,
379
+ return_stdout: bool = False,
380
+ return_stderr: bool = False,
381
+ logger: LoggerLike | None = None,
382
+ retry: tuple[int, TimeDelta] | None = None,
383
+ ) -> str | None: ...
358
384
  def ssh(
359
385
  user: str,
360
386
  hostname: str,
@@ -371,6 +397,7 @@ def ssh(
371
397
  return_stdout: bool = False,
372
398
  return_stderr: bool = False,
373
399
  logger: LoggerLike | None = None,
400
+ retry: tuple[int, TimeDelta] | None = None,
374
401
  ) -> str | None:
375
402
  cmd_and_args = ssh_cmd( # skipif-ci
376
403
  user,
@@ -380,17 +407,61 @@ def ssh(
380
407
  host_key_algorithms=host_key_algorithms,
381
408
  strict_host_key_checking=strict_host_key_checking,
382
409
  )
383
- return run( # skipif-ci
384
- *cmd_and_args,
385
- input=input,
386
- print=print,
387
- print_stdout=print_stdout,
388
- print_stderr=print_stderr,
389
- return_=return_,
390
- return_stdout=return_stdout,
391
- return_stderr=return_stderr,
392
- logger=logger,
393
- )
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
+ )
394
465
 
395
466
 
396
467
  def ssh_cmd(