dycw-utilities 0.175.14__py3-none-any.whl → 0.175.16__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.175.14
3
+ Version: 0.175.16
4
4
  Summary: Miscellaneous Python utilities
5
5
  Author: Derek Wan
6
6
  Author-email: Derek Wan <d.wan@icloud.com>
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=BPQLImIyoL3MqLo2IQpQFaliGFVZmxQJLSwMiVrwkhA,61
1
+ utilities/__init__.py,sha256=T7O3-BYhuabAFjqxaQs9o5WOToPVSLS3TN_UrDKm1-o,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
@@ -25,7 +25,7 @@ utilities/gzip.py,sha256=fkGP3KdsBfXlstodT4wtlp-PwNyUsogpbDCVVVGdsm4,781
25
25
  utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
26
26
  utilities/http.py,sha256=TsavEfHlRtlLaeV21Z6KZh0qbPw-kvD1zsQdZ7Kep5Q,977
27
27
  utilities/hypothesis.py,sha256=NUu30pl5kjL3tzo-m8SMRwTqLAmTWK-_Sau2NemJcQo,46773
28
- utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
28
+ utilities/importlib.py,sha256=SkVVtIjVC7bjJ36doXnmnmFiYe5tLbip4YAfYJj8Ycg,892
29
29
  utilities/inflect.py,sha256=v7YkOWSu8NAmVghPcf4F3YBZQoJCS47_DLf9jbfWIs0,581
30
30
  utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
31
31
  utilities/iterables.py,sha256=t2TsW-K3rVlS6y4_tqcc1fk9RwJV-bi7G_VwduMABK0,42558
@@ -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=pagoVFbp_xJyHk4hei3vwZnaSZuMKgodKY6KF1ToqX8,42379
83
+ utilities/subprocess.py,sha256=nFPIXVzXomI_Oby8PYF9HNWrsWtcSsCtgFnj_22QYlI,43753
84
84
  utilities/tempfile.py,sha256=QyvIdfV4r4YZ0NeNYsg0tCijThLKa7Z32u5Kxy6ZsGo,3619
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.14.dist-info/WHEEL,sha256=RRVLqVugUmFOqBedBFAmA4bsgFcROUBiSUKlERi0Hcg,79
101
- dycw_utilities-0.175.14.dist-info/entry_points.txt,sha256=cOGtKeJI0KXLSV7MJ8Dhc2G8jPgDcBDm53MVNJU4ycI,136
102
- dycw_utilities-0.175.14.dist-info/METADATA,sha256=2aXs3olCrTO08_DVJn8u6uvXpl6IQpm2yiNY6oxUcVA,1443
103
- dycw_utilities-0.175.14.dist-info/RECORD,,
100
+ dycw_utilities-0.175.16.dist-info/WHEEL,sha256=RRVLqVugUmFOqBedBFAmA4bsgFcROUBiSUKlERi0Hcg,79
101
+ dycw_utilities-0.175.16.dist-info/entry_points.txt,sha256=cOGtKeJI0KXLSV7MJ8Dhc2G8jPgDcBDm53MVNJU4ycI,136
102
+ dycw_utilities-0.175.16.dist-info/METADATA,sha256=I6NeFafea7kKkUKz82clljp9LupC0JkQ0AgxoPvke34,1443
103
+ dycw_utilities-0.175.16.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.175.14"
3
+ __version__ = "0.175.16"
utilities/importlib.py CHANGED
@@ -1,7 +1,23 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import importlib.resources
3
4
  from importlib import import_module
4
5
  from importlib.util import find_spec
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING
8
+
9
+ from utilities.errors import ImpossibleCaseError
10
+
11
+ if TYPE_CHECKING:
12
+ from importlib.resources import Anchor
13
+
14
+
15
+ def files(*, anchor: Anchor | None = None) -> Path:
16
+ """Get the path for an anchor."""
17
+ path = importlib.resources.files(anchor)
18
+ if isinstance(path, Path):
19
+ return path
20
+ raise ImpossibleCaseError(case=[f"{path=}"]) # pragma: no cover
5
21
 
6
22
 
7
23
  def is_valid_import(module: str, /, *, name: str | None = None) -> bool:
@@ -15,4 +31,4 @@ def is_valid_import(module: str, /, *, name: str | None = None) -> bool:
15
31
  return hasattr(mod, name)
16
32
 
17
33
 
18
- __all__ = ["is_valid_import"]
34
+ __all__ = ["files", "is_valid_import"]
utilities/subprocess.py CHANGED
@@ -43,6 +43,7 @@ _HOST_KEY_ALGORITHMS = ["ssh-ed25519"]
43
43
  APT_UPDATE = ["apt", "update", "-y"]
44
44
  BASH_LC = ["bash", "-lc"]
45
45
  BASH_LS = ["bash", "-ls"]
46
+ CHPASSWD = "chpasswd"
46
47
  GIT_BRANCH_SHOW_CURRENT = ["git", "branch", "--show-current"]
47
48
  KNOWN_HOSTS = Path.home() / ".ssh/known_hosts"
48
49
  MKTEMP_DIR_CMD = ["mktemp", "-d"]
@@ -92,9 +93,6 @@ def chmod(path: PathLike, perms: PermissionsLike, /, *, sudo: bool = False) -> N
92
93
  Path(path).chmod(int(ensure_perms(perms)))
93
94
 
94
95
 
95
- ##
96
-
97
-
98
96
  def chmod_cmd(path: PathLike, perms: PermissionsLike, /) -> list[str]:
99
97
  """Command to use 'chmod' to change file mode."""
100
98
  return ["chmod", str(ensure_perms(perms)), str(path)]
@@ -134,9 +132,6 @@ def chown(
134
132
  assert_never(never)
135
133
 
136
134
 
137
- ##
138
-
139
-
140
135
  def chown_cmd(
141
136
  path: PathLike, /, *, user: str | int | None = None, group: str | int | None = None
142
137
  ) -> list[str]:
@@ -165,6 +160,16 @@ class ChownCmdError(Exception):
165
160
  ##
166
161
 
167
162
 
163
+ def chpasswd(user_name: str, password: str, /, *, sudo: bool = False) -> None:
164
+ """Update passwords."""
165
+ run( # pragma: no cover
166
+ *maybe_sudo_cmd(CHPASSWD, sudo=sudo), input=f"{user_name}:{password}"
167
+ )
168
+
169
+
170
+ ##
171
+
172
+
168
173
  def cp(
169
174
  src: PathLike,
170
175
  dest: PathLike,
@@ -1232,15 +1237,15 @@ def sudo_nopasswd_cmd(user: str, /) -> str:
1232
1237
  ##
1233
1238
 
1234
1239
 
1235
- def symlink(targret: PathLike, link: PathLike, /, *, sudo: bool = False) -> None:
1240
+ def symlink(target: PathLike, link: PathLike, /, *, sudo: bool = False) -> None:
1236
1241
  """Make a symbolic link."""
1237
1242
  rm(link, sudo=sudo)
1238
1243
  mkdir(link, sudo=sudo, parent=True)
1239
1244
  if sudo: # pragma: no cover
1240
- run(*sudo_cmd(*symlink_cmd(targret, link)))
1245
+ run(*sudo_cmd(*symlink_cmd(target, link)))
1241
1246
  else:
1242
- targret, link = map(Path, [targret, link])
1243
- link.symlink_to(targret)
1247
+ target, link = map(Path, [target, link])
1248
+ link.symlink_to(target)
1244
1249
 
1245
1250
 
1246
1251
  def symlink_cmd(target: PathLike, link: PathLike, /) -> list[str]:
@@ -1288,12 +1293,54 @@ def touch_cmd(path: PathLike, /) -> list[str]:
1288
1293
 
1289
1294
 
1290
1295
  def update_ca_certificates(*, sudo: bool = False) -> None:
1296
+ """Update the system CA certificates."""
1291
1297
  run(*maybe_sudo_cmd(UPDATE_CA_CERTIFICATES, sudo=sudo)) # pragma: no cover
1292
1298
 
1293
1299
 
1294
1300
  ##
1295
1301
 
1296
1302
 
1303
+ def useradd(
1304
+ login: str,
1305
+ /,
1306
+ *,
1307
+ create_home: bool = True,
1308
+ groups: MaybeIterable[str] | None = None,
1309
+ shell: PathLike | None = None,
1310
+ sudo: bool = False,
1311
+ password: str | None = None,
1312
+ ) -> None:
1313
+ """Create a new user."""
1314
+ args = maybe_sudo_cmd( # pragma: no cover
1315
+ *useradd_cmd(login, create_home=create_home, groups=groups, shell=shell)
1316
+ )
1317
+ run(*args) # pragma: no cover
1318
+ if password is not None: # pragma: no cover
1319
+ chpasswd(login, password, sudo=sudo)
1320
+
1321
+
1322
+ def useradd_cmd(
1323
+ login: str,
1324
+ /,
1325
+ *,
1326
+ create_home: bool = True,
1327
+ groups: MaybeIterable[str] | None = None,
1328
+ shell: PathLike | None = None,
1329
+ ) -> list[str]:
1330
+ """Command to use 'useradd' to create a new user."""
1331
+ args: list[str] = ["useradd"]
1332
+ if create_home:
1333
+ args.append("--create-home")
1334
+ if groups is not None:
1335
+ args.extend(["--groups", *always_iterable(groups)])
1336
+ if shell is not None:
1337
+ args.extend(["--shell", str(shell)])
1338
+ return [*args, login]
1339
+
1340
+
1341
+ ##
1342
+
1343
+
1297
1344
  @overload
1298
1345
  def uv_run(
1299
1346
  module: str,
@@ -1456,6 +1503,7 @@ __all__ = [
1456
1503
  "APT_UPDATE",
1457
1504
  "BASH_LC",
1458
1505
  "BASH_LS",
1506
+ "CHPASSWD",
1459
1507
  "GIT_BRANCH_SHOW_CURRENT",
1460
1508
  "MKTEMP_DIR_CMD",
1461
1509
  "RESTART_SSHD",
@@ -1473,6 +1521,7 @@ __all__ = [
1473
1521
  "chmod_cmd",
1474
1522
  "chown",
1475
1523
  "chown_cmd",
1524
+ "chpasswd",
1476
1525
  "cp",
1477
1526
  "cp_cmd",
1478
1527
  "echo_cmd",
@@ -1514,6 +1563,8 @@ __all__ = [
1514
1563
  "touch",
1515
1564
  "touch_cmd",
1516
1565
  "update_ca_certificates",
1566
+ "useradd",
1567
+ "useradd_cmd",
1517
1568
  "uv_run",
1518
1569
  "uv_run_cmd",
1519
1570
  "yield_git_repo",