dycw-utilities 0.174.4__py3-none-any.whl → 0.174.6__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.
- {dycw_utilities-0.174.4.dist-info → dycw_utilities-0.174.6.dist-info}/METADATA +1 -1
- {dycw_utilities-0.174.4.dist-info → dycw_utilities-0.174.6.dist-info}/RECORD +6 -6
- utilities/__init__.py +1 -1
- utilities/subprocess.py +116 -8
- {dycw_utilities-0.174.4.dist-info → dycw_utilities-0.174.6.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.174.4.dist-info → dycw_utilities-0.174.6.dist-info}/entry_points.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
utilities/__init__.py,sha256=
|
|
1
|
+
utilities/__init__.py,sha256=3pVEXocwWUcnyWJHWq_I_o96RALb2ltauJoGiOsfki8,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=
|
|
83
|
+
utilities/subprocess.py,sha256=qrPDBTVKy_RMTnNFD4mQ7iYlNncXQiDBGJhffh6K0uc,18216
|
|
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.
|
|
101
|
-
dycw_utilities-0.174.
|
|
102
|
-
dycw_utilities-0.174.
|
|
103
|
-
dycw_utilities-0.174.
|
|
100
|
+
dycw_utilities-0.174.6.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
|
|
101
|
+
dycw_utilities-0.174.6.dist-info/entry_points.txt,sha256=ykGI1ArwOPHqm2g5Cqh3ENdMxEej_a_FcOUov5EM5Oc,155
|
|
102
|
+
dycw_utilities-0.174.6.dist-info/METADATA,sha256=9UHGH9P99oGq0OZI0ERbOeM_X2x3M2EO6C3-xo16np4,1709
|
|
103
|
+
dycw_utilities-0.174.6.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/subprocess.py
CHANGED
|
@@ -2,13 +2,14 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
4
|
from contextlib import contextmanager
|
|
5
|
+
from dataclasses import dataclass
|
|
5
6
|
from io import StringIO
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from string import Template
|
|
8
9
|
from subprocess import PIPE, CalledProcessError, Popen
|
|
9
10
|
from threading import Thread
|
|
10
11
|
from time import sleep
|
|
11
|
-
from typing import IO, TYPE_CHECKING, Literal, assert_never, overload
|
|
12
|
+
from typing import IO, TYPE_CHECKING, Literal, assert_never, overload, override
|
|
12
13
|
|
|
13
14
|
from utilities.errors import ImpossibleCaseError
|
|
14
15
|
from utilities.logging import to_logger
|
|
@@ -22,9 +23,56 @@ if TYPE_CHECKING:
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
_HOST_KEY_ALGORITHMS = ["ssh-ed25519"]
|
|
26
|
+
APT_UPDATE = ["apt", "update", "-y"]
|
|
25
27
|
BASH_LC = ["bash", "-lc"]
|
|
26
28
|
BASH_LS = ["bash", "-ls"]
|
|
27
29
|
MKTEMP_DIR_CMD = ["mktemp", "-d"]
|
|
30
|
+
RESTART_SSHD = ["systemctl", "restart", "sshd"]
|
|
31
|
+
UPDATE_CA_CERTIFICATES: str = "update-ca-certificates"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def apt_install_cmd(package: str, /) -> list[str]:
|
|
35
|
+
return ["apt", "install", "-y", package]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def cat_cmd(path: PathLike, /) -> list[str]:
|
|
39
|
+
return ["cat", str(path)]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def cd_cmd(path: PathLike, /) -> list[str]:
|
|
43
|
+
return ["cd", str(path)]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def chmod_cmd(path: PathLike, mode: str, /) -> list[str]:
|
|
47
|
+
return ["chmod", mode, str(path)]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def chown_cmd(
|
|
51
|
+
path: PathLike, /, *, user: str | None = None, group: str | None = None
|
|
52
|
+
) -> list[str]:
|
|
53
|
+
match user, group:
|
|
54
|
+
case None, None:
|
|
55
|
+
raise ChownCmdError
|
|
56
|
+
case str(), None:
|
|
57
|
+
ownership = "user"
|
|
58
|
+
case None, str():
|
|
59
|
+
ownership = f":{group}"
|
|
60
|
+
case str(), str():
|
|
61
|
+
ownership = f"{user}:{group}"
|
|
62
|
+
case never:
|
|
63
|
+
assert_never(never)
|
|
64
|
+
return ["chown", ownership, str(path)]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(kw_only=True, slots=True)
|
|
68
|
+
class ChownCmdError(Exception):
|
|
69
|
+
@override
|
|
70
|
+
def __str__(self) -> str:
|
|
71
|
+
return "At least one of 'user' and/or 'group' must be given; got None"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def cp_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
75
|
+
return ["cp", "-r", str(src), str(dest)]
|
|
28
76
|
|
|
29
77
|
|
|
30
78
|
def echo_cmd(text: str, /) -> list[str]:
|
|
@@ -41,6 +89,15 @@ def expand_path(
|
|
|
41
89
|
return Path(path).expanduser()
|
|
42
90
|
|
|
43
91
|
|
|
92
|
+
def git_clone_cmd(url: str, path: PathLike, /) -> list[str]:
|
|
93
|
+
return ["git", "clone", "--recurse-submodules", url, str(path)]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def git_hard_reset_cmd(*, branch: str | None = None) -> list[str]:
|
|
97
|
+
branch_use = "master" if branch is None else branch
|
|
98
|
+
return ["git", "hard-reset", branch_use]
|
|
99
|
+
|
|
100
|
+
|
|
44
101
|
def maybe_sudo_cmd(cmd: str, /, *args: str, sudo: bool = False) -> list[str]:
|
|
45
102
|
parts: list[str] = [cmd, *args]
|
|
46
103
|
return sudo_cmd(*parts) if sudo else parts
|
|
@@ -60,6 +117,10 @@ def mkdir_cmd(path: PathLike, /, *, parent: bool = False) -> list[str]:
|
|
|
60
117
|
return ["mkdir", "-p", str(path_use)]
|
|
61
118
|
|
|
62
119
|
|
|
120
|
+
def mv_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
121
|
+
return ["mv", str(src), str(dest)]
|
|
122
|
+
|
|
123
|
+
|
|
63
124
|
def rm_cmd(path: PathLike, /) -> list[str]:
|
|
64
125
|
return ["rm", "-rf", str(path)]
|
|
65
126
|
|
|
@@ -216,8 +277,8 @@ def run(
|
|
|
216
277
|
if proc.stderr is None: # pragma: no cover
|
|
217
278
|
raise ImpossibleCaseError(case=[f"{proc.stderr=}"])
|
|
218
279
|
with (
|
|
219
|
-
|
|
220
|
-
|
|
280
|
+
_run_yield_write(proc.stdout, *stdout_outputs),
|
|
281
|
+
_run_yield_write(proc.stderr, *stderr_outputs),
|
|
221
282
|
):
|
|
222
283
|
if input is not None:
|
|
223
284
|
_ = proc.stdin.write(input)
|
|
@@ -299,8 +360,8 @@ def run(
|
|
|
299
360
|
|
|
300
361
|
|
|
301
362
|
@contextmanager
|
|
302
|
-
def
|
|
303
|
-
thread = Thread(target=
|
|
363
|
+
def _run_yield_write(input_: IO[str], /, *outputs: IO[str]) -> Iterator[None]:
|
|
364
|
+
thread = Thread(target=_run_daemon_target, args=(input_, *outputs), daemon=True)
|
|
304
365
|
thread.start()
|
|
305
366
|
try:
|
|
306
367
|
yield
|
|
@@ -308,17 +369,21 @@ def _yield_write(input_: IO[str], /, *outputs: IO[str]) -> Iterator[None]:
|
|
|
308
369
|
thread.join()
|
|
309
370
|
|
|
310
371
|
|
|
311
|
-
def
|
|
372
|
+
def _run_daemon_target(input_: IO[str], /, *outputs: IO[str]) -> None:
|
|
312
373
|
with input_:
|
|
313
374
|
for text in iter(input_.readline, ""):
|
|
314
|
-
|
|
375
|
+
_run_write_to_streams(text, *outputs)
|
|
315
376
|
|
|
316
377
|
|
|
317
|
-
def
|
|
378
|
+
def _run_write_to_streams(text: str, /, *outputs: IO[str]) -> None:
|
|
318
379
|
for output in outputs:
|
|
319
380
|
_ = output.write(text)
|
|
320
381
|
|
|
321
382
|
|
|
383
|
+
def set_hostname_cmd(hostname: str, /) -> list[str]:
|
|
384
|
+
return ["hostnamectl", "set-hostname", hostname]
|
|
385
|
+
|
|
386
|
+
|
|
322
387
|
@overload
|
|
323
388
|
def ssh(
|
|
324
389
|
user: str,
|
|
@@ -472,14 +537,41 @@ def ssh_cmd(
|
|
|
472
537
|
return [*args, "-T", f"{user}@{hostname}", *cmd_and_cmds_or_args]
|
|
473
538
|
|
|
474
539
|
|
|
540
|
+
def ssh_keygen_cmd(hostname: str, /) -> list[str]:
|
|
541
|
+
return ["ssh-keygen", "-f", "~/.ssh/known_hosts", "-R", hostname]
|
|
542
|
+
|
|
543
|
+
|
|
475
544
|
def sudo_cmd(cmd: str, /, *args: str) -> list[str]:
|
|
476
545
|
return ["sudo", cmd, *args]
|
|
477
546
|
|
|
478
547
|
|
|
548
|
+
def sudo_nopasswd_cmd(user: str, /) -> str:
|
|
549
|
+
return f"{user} ALL=(ALL) NOPASSWD: ALL"
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def symlink_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
553
|
+
return ["ln", "-s", str(src), str(dest)]
|
|
554
|
+
|
|
555
|
+
|
|
479
556
|
def touch_cmd(path: PathLike, /) -> list[str]:
|
|
480
557
|
return ["touch", str(path)]
|
|
481
558
|
|
|
482
559
|
|
|
560
|
+
def uv_run_cmd(module: str, /, *args: str) -> list[str]:
|
|
561
|
+
return [
|
|
562
|
+
"uv",
|
|
563
|
+
"run",
|
|
564
|
+
"--no-dev",
|
|
565
|
+
"--active",
|
|
566
|
+
"--prerelease=disallow",
|
|
567
|
+
"--managed-python",
|
|
568
|
+
"python",
|
|
569
|
+
"-m",
|
|
570
|
+
module,
|
|
571
|
+
*args,
|
|
572
|
+
]
|
|
573
|
+
|
|
574
|
+
|
|
483
575
|
@contextmanager
|
|
484
576
|
def yield_ssh_temp_dir(
|
|
485
577
|
user: str,
|
|
@@ -504,19 +596,35 @@ def yield_ssh_temp_dir(
|
|
|
504
596
|
|
|
505
597
|
|
|
506
598
|
__all__ = [
|
|
599
|
+
"APT_UPDATE",
|
|
507
600
|
"BASH_LC",
|
|
508
601
|
"BASH_LS",
|
|
509
602
|
"MKTEMP_DIR_CMD",
|
|
603
|
+
"RESTART_SSHD",
|
|
604
|
+
"UPDATE_CA_CERTIFICATES",
|
|
605
|
+
"ChownCmdError",
|
|
606
|
+
"apt_install_cmd",
|
|
607
|
+
"cd_cmd",
|
|
608
|
+
"chmod_cmd",
|
|
609
|
+
"chown_cmd",
|
|
610
|
+
"cp_cmd",
|
|
510
611
|
"echo_cmd",
|
|
511
612
|
"expand_path",
|
|
613
|
+
"git_clone_cmd",
|
|
614
|
+
"git_hard_reset_cmd",
|
|
512
615
|
"maybe_sudo_cmd",
|
|
513
616
|
"mkdir",
|
|
514
617
|
"mkdir_cmd",
|
|
618
|
+
"mv_cmd",
|
|
515
619
|
"rm_cmd",
|
|
516
620
|
"run",
|
|
621
|
+
"set_hostname_cmd",
|
|
517
622
|
"ssh",
|
|
518
623
|
"ssh_cmd",
|
|
519
624
|
"sudo_cmd",
|
|
625
|
+
"sudo_nopasswd_cmd",
|
|
626
|
+
"symlink_cmd",
|
|
520
627
|
"touch_cmd",
|
|
628
|
+
"uv_run_cmd",
|
|
521
629
|
"yield_ssh_temp_dir",
|
|
522
630
|
]
|
|
File without changes
|
|
File without changes
|