dycw-utilities 0.175.18__py3-none-any.whl → 0.175.19__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.175.18.dist-info → dycw_utilities-0.175.19.dist-info}/METADATA +1 -1
- {dycw_utilities-0.175.18.dist-info → dycw_utilities-0.175.19.dist-info}/RECORD +6 -6
- utilities/__init__.py +1 -1
- utilities/subprocess.py +71 -2
- {dycw_utilities-0.175.18.dist-info → dycw_utilities-0.175.19.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.175.18.dist-info → dycw_utilities-0.175.19.dist-info}/entry_points.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
utilities/__init__.py,sha256=
|
|
1
|
+
utilities/__init__.py,sha256=Icf2ql4qG7C1V1W6jJzw-EbFjcuaZSkx7-OyX1zNNMY,61
|
|
2
2
|
utilities/altair.py,sha256=TLfRFbG9HwG7SLXoJ-v0r-t49ZaGgTQZD82cpjVi4vs,9085
|
|
3
3
|
utilities/asyncio.py,sha256=aJySVxBY0gqsIYnoNmH7-1r8djKuf4vSsU69VCD08t8,16772
|
|
4
4
|
utilities/atomicwrites.py,sha256=tPo6r-Rypd9u99u66B9z86YBPpnLrlHtwox_8Z7T34Y,5790
|
|
@@ -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=F4sRJq9eNnXwZ46GgYxTQQCT-YUx_ghZ4o91dH4KgW4,45405
|
|
84
84
|
utilities/tempfile.py,sha256=a3_M1QyxGZql_VcGkBOQBeWbbkItjgkfIpVyzU1UAic,3843
|
|
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.175.
|
|
101
|
-
dycw_utilities-0.175.
|
|
102
|
-
dycw_utilities-0.175.
|
|
103
|
-
dycw_utilities-0.175.
|
|
100
|
+
dycw_utilities-0.175.19.dist-info/WHEEL,sha256=RRVLqVugUmFOqBedBFAmA4bsgFcROUBiSUKlERi0Hcg,79
|
|
101
|
+
dycw_utilities-0.175.19.dist-info/entry_points.txt,sha256=cOGtKeJI0KXLSV7MJ8Dhc2G8jPgDcBDm53MVNJU4ycI,136
|
|
102
|
+
dycw_utilities-0.175.19.dist-info/METADATA,sha256=-Ng54LQmTd_U_-Vbb0rRL7bAKisLDxfPhIrEkrxtT9U,1443
|
|
103
|
+
dycw_utilities-0.175.19.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/subprocess.py
CHANGED
|
@@ -5,6 +5,7 @@ import sys
|
|
|
5
5
|
from contextlib import contextmanager
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from io import StringIO
|
|
8
|
+
from itertools import repeat
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from re import search
|
|
10
11
|
from shlex import join
|
|
@@ -54,11 +55,36 @@ UPDATE_CA_CERTIFICATES: str = "update-ca-certificates"
|
|
|
54
55
|
##
|
|
55
56
|
|
|
56
57
|
|
|
58
|
+
def append_text(
|
|
59
|
+
path: PathLike,
|
|
60
|
+
text: str,
|
|
61
|
+
/,
|
|
62
|
+
*,
|
|
63
|
+
sudo: bool = False,
|
|
64
|
+
skip_if_present: bool = False,
|
|
65
|
+
flags: int = 0,
|
|
66
|
+
blank_lines: int = 1,
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Append text to a file."""
|
|
69
|
+
try:
|
|
70
|
+
existing = cat(path, sudo=sudo)
|
|
71
|
+
except (CalledProcessError, FileNotFoundError):
|
|
72
|
+
tee(path, text, sudo=sudo, append=True)
|
|
73
|
+
return
|
|
74
|
+
if skip_if_present and (search(text, existing, flags=flags) is not None):
|
|
75
|
+
return
|
|
76
|
+
full = "".join([*repeat("\n", times=blank_lines), text])
|
|
77
|
+
tee(path, full, sudo=sudo, append=True)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
##
|
|
81
|
+
|
|
82
|
+
|
|
57
83
|
def apt_install(package: str, /, *, update: bool = False, sudo: bool = False) -> None:
|
|
58
84
|
"""Install a package."""
|
|
59
85
|
if update: # pragma: no cover
|
|
60
86
|
run(*maybe_sudo_cmd(*APT_UPDATE, sudo=sudo))
|
|
61
|
-
run(*maybe_sudo_cmd(*apt_install_cmd(package), sudo=sudo))
|
|
87
|
+
run(*maybe_sudo_cmd(*apt_install_cmd(package), sudo=sudo)) # pragma: no cover
|
|
62
88
|
|
|
63
89
|
|
|
64
90
|
def apt_install_cmd(package: str, /) -> list[str]:
|
|
@@ -69,6 +95,13 @@ def apt_install_cmd(package: str, /) -> list[str]:
|
|
|
69
95
|
##
|
|
70
96
|
|
|
71
97
|
|
|
98
|
+
def cat(path: PathLike, /, *, sudo: bool = False) -> str:
|
|
99
|
+
"""Concatenate a file."""
|
|
100
|
+
if sudo: # pragma: no cover
|
|
101
|
+
return run(*sudo_cmd(*cat_cmd(path)), return_=True)
|
|
102
|
+
return Path(path).read_text()
|
|
103
|
+
|
|
104
|
+
|
|
72
105
|
def cat_cmd(path: PathLike, /) -> list[str]:
|
|
73
106
|
"""Command to use 'cat' to concatenate and print files."""
|
|
74
107
|
return ["cat", str(path)]
|
|
@@ -170,6 +203,24 @@ def chpasswd(user_name: str, password: str, /, *, sudo: bool = False) -> None:
|
|
|
170
203
|
##
|
|
171
204
|
|
|
172
205
|
|
|
206
|
+
def copy_text(
|
|
207
|
+
src: PathLike,
|
|
208
|
+
dest: PathLike,
|
|
209
|
+
/,
|
|
210
|
+
*,
|
|
211
|
+
sudo: bool = False,
|
|
212
|
+
substitutions: StrMapping | None = None,
|
|
213
|
+
) -> None:
|
|
214
|
+
"""Copy the text contents of a file."""
|
|
215
|
+
text = cat(src, sudo=sudo)
|
|
216
|
+
if substitutions is not None:
|
|
217
|
+
text = Template(text).substitute(**substitutions)
|
|
218
|
+
tee(dest, text, sudo=sudo)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
##
|
|
222
|
+
|
|
223
|
+
|
|
173
224
|
def cp(
|
|
174
225
|
src: PathLike,
|
|
175
226
|
dest: PathLike,
|
|
@@ -356,6 +407,20 @@ def mv_cmd(src: PathLike, dest: PathLike, /) -> list[str]:
|
|
|
356
407
|
##
|
|
357
408
|
|
|
358
409
|
|
|
410
|
+
def replace_text(
|
|
411
|
+
path: PathLike, /, *replacements: tuple[str, str], sudo: bool = False
|
|
412
|
+
) -> None:
|
|
413
|
+
"""Replace the text in a file."""
|
|
414
|
+
path = Path(path)
|
|
415
|
+
text = cat(path, sudo=sudo)
|
|
416
|
+
for old, new in replacements:
|
|
417
|
+
text = text.replace(old, new)
|
|
418
|
+
tee(path, text, sudo=sudo)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
##
|
|
422
|
+
|
|
423
|
+
|
|
359
424
|
def ripgrep(*args: str, path: PathLike = PWD) -> str | None:
|
|
360
425
|
"""Search for lines."""
|
|
361
426
|
try: # skipif-ci
|
|
@@ -1260,7 +1325,7 @@ def symlink_cmd(target: PathLike, link: PathLike, /) -> list[str]:
|
|
|
1260
1325
|
def tee(
|
|
1261
1326
|
path: PathLike, text: str, /, *, sudo: bool = False, append: bool = False
|
|
1262
1327
|
) -> None:
|
|
1263
|
-
"""
|
|
1328
|
+
"""Duplicate standard input."""
|
|
1264
1329
|
mkdir(path, sudo=sudo, parent=True)
|
|
1265
1330
|
if sudo: # pragma: no cover
|
|
1266
1331
|
run(*sudo_cmd(*tee_cmd(path, append=append)), input=text)
|
|
@@ -1516,14 +1581,17 @@ __all__ = [
|
|
|
1516
1581
|
"RsyncCmdError",
|
|
1517
1582
|
"RsyncCmdNoSourcesError",
|
|
1518
1583
|
"RsyncCmdSourcesNotFoundError",
|
|
1584
|
+
"append_text",
|
|
1519
1585
|
"apt_install",
|
|
1520
1586
|
"apt_install_cmd",
|
|
1587
|
+
"cat",
|
|
1521
1588
|
"cd_cmd",
|
|
1522
1589
|
"chmod",
|
|
1523
1590
|
"chmod_cmd",
|
|
1524
1591
|
"chown",
|
|
1525
1592
|
"chown_cmd",
|
|
1526
1593
|
"chpasswd",
|
|
1594
|
+
"copy_text",
|
|
1527
1595
|
"cp",
|
|
1528
1596
|
"cp_cmd",
|
|
1529
1597
|
"echo_cmd",
|
|
@@ -1540,6 +1608,7 @@ __all__ = [
|
|
|
1540
1608
|
"mkdir_cmd",
|
|
1541
1609
|
"mv",
|
|
1542
1610
|
"mv_cmd",
|
|
1611
|
+
"replace_text",
|
|
1543
1612
|
"ripgrep",
|
|
1544
1613
|
"ripgrep_cmd",
|
|
1545
1614
|
"rm",
|
|
File without changes
|
|
File without changes
|