dycw-actions 0.8.5__py3-none-any.whl → 0.8.11__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.
@@ -12,12 +12,12 @@ from libcst import Module, parse_module
12
12
  from rich.pretty import pretty_repr
13
13
  from tomlkit import TOMLDocument, aot, array, document, string, table
14
14
  from tomlkit.items import AoT, Array, Table
15
- from utilities.functions import ensure_class, ensure_str
15
+ from utilities.functions import ensure_class, ensure_str, get_func_name
16
16
  from utilities.iterables import OneEmptyError, OneNonUniqueError, one
17
17
  from utilities.packaging import Requirement
18
18
  from utilities.types import PathLike, StrDict
19
19
 
20
- from actions.constants import YAML_INSTANCE
20
+ from actions.constants import PATH_CACHE, YAML_INSTANCE
21
21
  from actions.logging import LOGGER
22
22
  from actions.utilities import are_equal_modulo_new_line, write_text, yaml_dump
23
23
 
@@ -222,76 +222,10 @@ class PyProjectDependencies:
222
222
  ##
223
223
 
224
224
 
225
- @contextmanager
226
- def yield_json_dict(
227
- path: PathLike, /, *, modifications: MutableSet[Path] | None = None
228
- ) -> Iterator[StrDict]:
229
- with yield_mutable_write_context(
230
- path, json.loads, dict, json.dumps, modifications=modifications
231
- ) as dict_:
232
- yield dict_
233
-
234
-
235
- ##
236
-
237
-
238
- @contextmanager
239
- def yield_python_file(
240
- path: PathLike, /, *, modifications: MutableSet[Path] | None = None
241
- ) -> Iterator[WriteContext[Module]]:
242
- with yield_immutable_write_context(
243
- path,
244
- parse_module,
245
- lambda: Module(body=[]),
246
- lambda module: module.code,
247
- modifications=modifications,
248
- ) as context:
249
- yield context
250
-
251
-
252
- ##
253
-
254
-
255
- @contextmanager
256
- def yield_text_file(
257
- path: PathLike, /, *, modifications: MutableSet[Path] | None = None
258
- ) -> Iterator[WriteContext[str]]:
259
- with yield_immutable_write_context(
260
- path, str, lambda: "", str, modifications=modifications
261
- ) as context:
262
- yield context
263
-
264
-
265
- ##
266
-
267
-
268
- @contextmanager
269
- def yield_toml_doc(
270
- path: PathLike, /, *, modifications: MutableSet[Path] | None = None
271
- ) -> Iterator[TOMLDocument]:
272
- with yield_mutable_write_context(
273
- path, tomlkit.parse, document, tomlkit.dumps, modifications=modifications
274
- ) as doc:
275
- yield doc
276
-
277
-
278
- ##
279
-
280
-
281
- @contextmanager
282
- def yield_mutable_write_context[T](
283
- path: PathLike,
284
- loads: Callable[[str], T],
285
- get_default: Callable[[], T],
286
- dumps: Callable[[T], str],
287
- /,
288
- *,
289
- modifications: MutableSet[Path] | None = None,
290
- ) -> Iterator[T]:
291
- with yield_immutable_write_context(
292
- path, loads, get_default, dumps, modifications=modifications
293
- ) as context:
294
- yield context.output
225
+ def path_throttle_cache(func: Callable[..., Any]) -> Path:
226
+ func_name = get_func_name(func)
227
+ cwd_name = Path.cwd().name
228
+ return PATH_CACHE / "throttle" / f"{func_name}--{cwd_name}"
295
229
 
296
230
 
297
231
  ##
@@ -348,6 +282,81 @@ def yield_immutable_write_context[T](
348
282
  ##
349
283
 
350
284
 
285
+ @contextmanager
286
+ def yield_json_dict(
287
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
288
+ ) -> Iterator[StrDict]:
289
+ with yield_mutable_write_context(
290
+ path, json.loads, dict, json.dumps, modifications=modifications
291
+ ) as dict_:
292
+ yield dict_
293
+
294
+
295
+ ##
296
+
297
+
298
+ @contextmanager
299
+ def yield_mutable_write_context[T](
300
+ path: PathLike,
301
+ loads: Callable[[str], T],
302
+ get_default: Callable[[], T],
303
+ dumps: Callable[[T], str],
304
+ /,
305
+ *,
306
+ modifications: MutableSet[Path] | None = None,
307
+ ) -> Iterator[T]:
308
+ with yield_immutable_write_context(
309
+ path, loads, get_default, dumps, modifications=modifications
310
+ ) as context:
311
+ yield context.output
312
+
313
+
314
+ ##
315
+
316
+
317
+ @contextmanager
318
+ def yield_python_file(
319
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
320
+ ) -> Iterator[WriteContext[Module]]:
321
+ with yield_immutable_write_context(
322
+ path,
323
+ parse_module,
324
+ lambda: Module(body=[]),
325
+ lambda module: module.code,
326
+ modifications=modifications,
327
+ ) as context:
328
+ yield context
329
+
330
+
331
+ ##
332
+
333
+
334
+ @contextmanager
335
+ def yield_text_file(
336
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
337
+ ) -> Iterator[WriteContext[str]]:
338
+ with yield_immutable_write_context(
339
+ path, str, lambda: "", str, modifications=modifications
340
+ ) as context:
341
+ yield context
342
+
343
+
344
+ ##
345
+
346
+
347
+ @contextmanager
348
+ def yield_toml_doc(
349
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
350
+ ) -> Iterator[TOMLDocument]:
351
+ with yield_mutable_write_context(
352
+ path, tomlkit.parse, document, tomlkit.dumps, modifications=modifications
353
+ ) as doc:
354
+ yield doc
355
+
356
+
357
+ ##
358
+
359
+
351
360
  @contextmanager
352
361
  def yield_yaml_dict(
353
362
  path: PathLike, /, *, modifications: MutableSet[Path] | None = None
@@ -360,6 +369,7 @@ def yield_yaml_dict(
360
369
 
361
370
  __all__ = [
362
371
  "PyProjectDependencies",
372
+ "WriteContext",
363
373
  "ensure_aot_contains",
364
374
  "ensure_contains",
365
375
  "ensure_contains_partial_dict",
@@ -375,6 +385,7 @@ __all__ = [
375
385
  "get_table",
376
386
  "is_partial_dict",
377
387
  "is_partial_str",
388
+ "path_throttle_cache",
378
389
  "yield_immutable_write_context",
379
390
  "yield_json_dict",
380
391
  "yield_mutable_write_context",
@@ -3,12 +3,10 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from utilities.tempfile import TemporaryDirectory
6
- from utilities.text import strip_and_dedent
7
6
 
8
- from actions import __version__
9
7
  from actions.logging import LOGGER
10
8
  from actions.publish_package.settings import SETTINGS
11
- from actions.utilities import logged_run
9
+ from actions.utilities import log_func_call, logged_run
12
10
 
13
11
  if TYPE_CHECKING:
14
12
  from typed_settings import Secret
@@ -22,23 +20,14 @@ def publish_package(
22
20
  trusted_publishing: bool = SETTINGS.trusted_publishing,
23
21
  native_tls: bool = SETTINGS.native_tls,
24
22
  ) -> None:
25
- LOGGER.info(
26
- strip_and_dedent("""
27
- Running '%s' (version %s) with settings:
28
- - username = %s
29
- - password = %s
30
- - publish_url = %s
31
- - trusted_publishing = %s
32
- - native_tls = %s
33
- """),
34
- publish_package.__name__,
35
- __version__,
36
- username,
37
- password,
38
- publish_url,
39
- trusted_publishing,
40
- native_tls,
41
- )
23
+ variables = [
24
+ f"{username=}",
25
+ f"{password=}",
26
+ f"{publish_url=}",
27
+ f"{trusted_publishing=}",
28
+ f"{native_tls=}",
29
+ ]
30
+ LOGGER.info(log_func_call(publish_package, *variables))
42
31
  with TemporaryDirectory() as temp:
43
32
  logged_run("uv", "build", "--out-dir", str(temp), "--wheel", "--clear")
44
33
  logged_run(
@@ -16,8 +16,8 @@ def random_sleep_sub_cmd(settings: Settings, /) -> None:
16
16
  return
17
17
  basic_config(obj=LOGGER)
18
18
  random_sleep(
19
- min_=settings.min,
20
- max_=settings.max,
19
+ min=settings.min,
20
+ max=settings.max,
21
21
  step=settings.step,
22
22
  log_freq=settings.log_freq,
23
23
  )
@@ -4,39 +4,25 @@ from math import ceil, floor
4
4
  from random import choice
5
5
  from time import sleep
6
6
 
7
- from utilities.text import strip_and_dedent
8
7
  from utilities.whenever import get_now
9
8
  from whenever import TimeDelta, ZonedDateTime
10
9
 
11
- from actions import __version__
12
10
  from actions.logging import LOGGER
13
11
  from actions.random_sleep.settings import SETTINGS
12
+ from actions.utilities import log_func_call
14
13
 
15
14
 
16
15
  def random_sleep(
17
16
  *,
18
- min_: int = SETTINGS.min,
19
- max_: int = SETTINGS.max,
17
+ min: int = SETTINGS.min, # noqa: A002
18
+ max: int = SETTINGS.max, # noqa: A002
20
19
  step: int = SETTINGS.step,
21
20
  log_freq: int = SETTINGS.log_freq,
22
21
  ) -> None:
23
- LOGGER.info(
24
- strip_and_dedent("""
25
- Running '%s' (version %s) with settings:
26
- - min_ = %s
27
- - max_ = %s
28
- - step = %s
29
- - log_freq = %s
30
- """),
31
- random_sleep.__name__,
32
- __version__,
33
- min_,
34
- max_,
35
- step,
36
- log_freq,
37
- )
22
+ variables = [f"{min=}", f"{max=}", f"{step=}", f"{log_freq=}"]
23
+ LOGGER.info(log_func_call(random_sleep, *variables))
38
24
  start = get_now()
39
- delta = TimeDelta(seconds=choice(range(min_, max_, step)))
25
+ delta = TimeDelta(seconds=choice(range(min, max, step)))
40
26
  LOGGER.info("Sleeping for %s...", delta)
41
27
  end = (start + delta).round(mode="ceil")
42
28
  while (now := get_now()) < end:
@@ -7,10 +7,8 @@ from typing import TYPE_CHECKING
7
7
 
8
8
  from requests import get
9
9
  from utilities.atomicwrites import writer
10
- from utilities.subprocess import chmod, ssh
11
- from utilities.text import strip_and_dedent
10
+ from utilities.subprocess import chmod, rm_cmd, ssh, sudo_cmd
12
11
 
13
- from actions import __version__
14
12
  from actions.logging import LOGGER
15
13
  from actions.register_gitea_runner.constants import (
16
14
  PATH_CACHE,
@@ -19,7 +17,7 @@ from actions.register_gitea_runner.constants import (
19
17
  URL_WAIT_FOR_IT,
20
18
  )
21
19
  from actions.register_gitea_runner.settings import SETTINGS
22
- from actions.utilities import logged_run
20
+ from actions.utilities import log_func_call, logged_run
23
21
 
24
22
  if TYPE_CHECKING:
25
23
  from utilities.types import PathLike
@@ -39,33 +37,19 @@ def register_gitea_runner(
39
37
  runner_instance_name: str = SETTINGS.runner_instance_name,
40
38
  ) -> None:
41
39
  """Register against a remote instance of Gitea."""
42
- LOGGER.info(
43
- strip_and_dedent("""
44
- Running '%s' (version %s) with settings:
45
- - ssh_user = %s
46
- - ssh_host = %s
47
- - gitea_container_user = %s
48
- - gitea_container_name = %s
49
- - runner_certificate = %s
50
- - runner_capacity = %d
51
- - runner_container_name = %s
52
- - gitea_host = %s
53
- - gitea_port = %d
54
- - runner_instance_name = %s
55
- """),
56
- register_gitea_runner.__name__,
57
- __version__,
58
- ssh_user,
59
- ssh_host,
60
- gitea_container_user,
61
- gitea_container_name,
62
- runner_certificate,
63
- runner_capacity,
64
- runner_container_name,
65
- gitea_host,
66
- gitea_port,
67
- runner_instance_name,
68
- )
40
+ variables = [
41
+ f"{ssh_user=}",
42
+ f"{ssh_host=}",
43
+ f"{gitea_container_user=}",
44
+ f"{gitea_container_name=}",
45
+ f"{runner_certificate=}",
46
+ f"{runner_capacity=}",
47
+ f"{runner_container_name=}",
48
+ f"{gitea_host=}",
49
+ f"{gitea_port=}",
50
+ f"{runner_instance_name=}",
51
+ ]
52
+ LOGGER.info(log_func_call(register_gitea_runner, *variables))
69
53
  token = ssh(
70
54
  ssh_user,
71
55
  ssh_host,
@@ -237,7 +221,8 @@ def _start_runner(
237
221
  _write_config(token, capacity=runner_capacity, certificate=runner_certificate)
238
222
  _write_entrypoint(host=gitea_host, port=gitea_port)
239
223
  _write_wait_for_it()
240
- logged_run(*_docker_stop_runner_args(name=runner_container_name), print=True)
224
+ logged_run(*_docker_stop_runner_args(name=runner_container_name))
225
+ logged_run(*sudo_cmd(*rm_cmd("data")))
241
226
  logged_run(
242
227
  *_docker_run_act_runner_args(
243
228
  token,
@@ -246,8 +231,7 @@ def _start_runner(
246
231
  runner_certificate=runner_certificate,
247
232
  instance_name=runner_instance_name,
248
233
  container_name=runner_container_name,
249
- ),
250
- print=True,
234
+ )
251
235
  )
252
236
 
253
237
 
actions/run_hooks/lib.py CHANGED
@@ -8,14 +8,12 @@ from subprocess import CalledProcessError
8
8
  from typing import TYPE_CHECKING, Any
9
9
 
10
10
  from utilities.functions import ensure_class, ensure_str
11
- from utilities.text import strip_and_dedent
12
11
  from whenever import TimeDelta
13
12
  from yaml import safe_load
14
13
 
15
- from actions import __version__
16
14
  from actions.logging import LOGGER
17
15
  from actions.run_hooks.settings import SETTINGS
18
- from actions.utilities import logged_run
16
+ from actions.utilities import log_func_call, logged_run
19
17
 
20
18
  if TYPE_CHECKING:
21
19
  from collections.abc import Iterator
@@ -28,21 +26,8 @@ def run_hooks(
28
26
  hooks_exclude: list[str] | None = SETTINGS.hooks_exclude,
29
27
  sleep: int = SETTINGS.sleep,
30
28
  ) -> None:
31
- LOGGER.info(
32
- strip_and_dedent("""
33
- Running '%s' (version %s) with settings:
34
- - repos = %s
35
- - hooks = %s
36
- - hooks_exclude = %s
37
- - sleep = %d
38
- """),
39
- run_hooks.__name__,
40
- __version__,
41
- repos,
42
- hooks,
43
- hooks_exclude,
44
- sleep,
45
- )
29
+ variables = [f"{repos=}", f"{hooks=}", f"{hooks_exclude=}", f"{sleep=}"]
30
+ LOGGER.info(log_func_call(run_hooks, *variables))
46
31
  results = {
47
32
  hook: _run_hook(hook, sleep=sleep)
48
33
  for hook in _yield_hooks(repos=repos, hooks=hooks, hooks_exclude=hooks_exclude)
@@ -5,12 +5,11 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  from utilities.platform import SYSTEM
7
7
  from utilities.subprocess import chmod, chown, tee
8
- from utilities.text import strip_and_dedent
9
8
 
10
- from actions import __version__
11
9
  from actions.logging import LOGGER
12
10
  from actions.setup_cronjob.constants import PATH_CONFIGS
13
11
  from actions.setup_cronjob.settings import SETTINGS
12
+ from actions.utilities import log_func_call
14
13
 
15
14
  if TYPE_CHECKING:
16
15
  from collections.abc import Sequence
@@ -31,31 +30,18 @@ def setup_cronjob(
31
30
  logs_keep: int = SETTINGS.logs_keep,
32
31
  ) -> None:
33
32
  """Set up a cronjob & logrotate."""
34
- LOGGER.info(
35
- strip_and_dedent("""
36
- Running '%s' (version %s) with settings:
37
- - name = %s
38
- - prepend_path = %s
39
- - schedule = %s
40
- - user = %s
41
- - timeout = %d
42
- - kill_after = %d
43
- - command = %s
44
- - args = %s
45
- - logs_keep = %d
46
- """),
47
- setup_cronjob.__name__,
48
- __version__,
49
- name,
50
- prepend_path,
51
- schedule,
52
- user,
53
- timeout,
54
- kill_after,
55
- command,
56
- args,
57
- logs_keep,
58
- )
33
+ variables = [
34
+ f"{name=}",
35
+ f"{prepend_path=}",
36
+ f"{schedule=}",
37
+ f"{user=}",
38
+ f"{timeout=}",
39
+ f"{kill_after=}",
40
+ f"{command=}",
41
+ f"{args=}",
42
+ f"{logs_keep=}",
43
+ ]
44
+ LOGGER.info(log_func_call(setup_cronjob, *variables))
59
45
  if SYSTEM != "linux":
60
46
  msg = f"System must be 'linux'; got {SYSTEM!r}"
61
47
  raise TypeError(msg)
actions/tag_commit/lib.py CHANGED
@@ -3,13 +3,11 @@ from __future__ import annotations
3
3
  from contextlib import suppress
4
4
  from subprocess import CalledProcessError
5
5
 
6
- from utilities.text import strip_and_dedent
7
6
  from utilities.version import parse_version
8
7
 
9
- from actions import __version__
10
8
  from actions.logging import LOGGER
11
9
  from actions.tag_commit.settings import SETTINGS
12
- from actions.utilities import logged_run
10
+ from actions.utilities import log_func_call, logged_run
13
11
 
14
12
 
15
13
  def tag_commit(
@@ -20,23 +18,14 @@ def tag_commit(
20
18
  major: bool = SETTINGS.major,
21
19
  latest: bool = SETTINGS.latest,
22
20
  ) -> None:
23
- LOGGER.info(
24
- strip_and_dedent("""
25
- Running '%s' (version %s) with settings:
26
- - user_name = %s
27
- - user_email = %s
28
- - major_minor = %s
29
- - major = %s
30
- - latest = %s
31
- """),
32
- tag_commit.__name__,
33
- __version__,
34
- user_name,
35
- user_email,
36
- major_minor,
37
- major,
38
- latest,
39
- )
21
+ variables = [
22
+ f"{user_name=}",
23
+ f"{user_email=}",
24
+ f"{major_minor=}",
25
+ f"{major=}",
26
+ f"{latest=}",
27
+ ]
28
+ LOGGER.info(log_func_call(tag_commit, *variables))
40
29
  logged_run("git", "config", "--global", "user.name", user_name)
41
30
  logged_run("git", "config", "--global", "user.email", user_email)
42
31
  version = parse_version(
actions/utilities.py CHANGED
@@ -2,17 +2,22 @@ from __future__ import annotations
2
2
 
3
3
  from io import StringIO
4
4
  from pathlib import Path
5
+ from textwrap import indent
5
6
  from typing import TYPE_CHECKING, Any, Literal, assert_never, overload
6
7
 
8
+ from tabulate import tabulate
7
9
  from typed_settings import EnvLoader, Secret
8
10
  from utilities.atomicwrites import writer
11
+ from utilities.functions import get_func_name
9
12
  from utilities.subprocess import run
13
+ from utilities.text import split_str
10
14
 
15
+ from actions import __version__
11
16
  from actions.constants import YAML_INSTANCE
12
17
  from actions.logging import LOGGER
13
18
 
14
19
  if TYPE_CHECKING:
15
- from collections.abc import MutableSet
20
+ from collections.abc import Callable, MutableSet
16
21
 
17
22
  from utilities.types import PathLike, StrStrMapping
18
23
 
@@ -82,6 +87,17 @@ def ensure_new_line(text: str, /) -> str:
82
87
  return text.strip("\n") + "\n"
83
88
 
84
89
 
90
+ def log_func_call(func: Callable[..., Any], /, *variables: str) -> str:
91
+ name = get_func_name(func)
92
+ table = tabulate(
93
+ list(map(split_f_str_equals, variables)), tablefmt="rounded_outline"
94
+ )
95
+ indented = indent(table, " ")
96
+ return f"""
97
+ Running {name!r} (version {__version__}) with:
98
+ {indented}"""
99
+
100
+
85
101
  @overload
86
102
  def logged_run(
87
103
  cmd: SecretLike,
@@ -131,6 +147,11 @@ def logged_run(
131
147
  return run(*unwrapped, env=env, print=print, return_=return_, logger=LOGGER)
132
148
 
133
149
 
150
+ def split_f_str_equals(text: str, /) -> tuple[str, str]:
151
+ """Split an `f`-string with `=`."""
152
+ return split_str(text, separator="=", n=2)
153
+
154
+
134
155
  def write_text(
135
156
  path: PathLike, text: str, /, *, modifications: MutableSet[Path] | None = None
136
157
  ) -> None:
@@ -159,6 +180,7 @@ __all__ = [
159
180
  "copy_text",
160
181
  "ensure_new_line",
161
182
  "logged_run",
183
+ "split_f_str_equals",
162
184
  "write_text",
163
185
  "yaml_dump",
164
186
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dycw-actions
3
- Version: 0.8.5
3
+ Version: 0.8.11
4
4
  Summary: Library of actions
5
5
  Requires-Dist: click>=8.3.1,<9
6
6
  Requires-Dist: dycw-utilities>=0.179.0,<1
@@ -12,6 +12,7 @@ Requires-Dist: pyyaml>=6.0.3,<7
12
12
  Requires-Dist: requests>=2.32.5,<3
13
13
  Requires-Dist: rich>=14.2.0,<15
14
14
  Requires-Dist: ruamel-yaml>=0.19.1,<1
15
+ Requires-Dist: tabulate>=0.9.0,<1
15
16
  Requires-Dist: tomlkit>=0.13.3,<1
16
17
  Requires-Dist: typed-settings[attrs,click]>=25.3.0,<26
17
18
  Requires-Dist: xdg-base-dirs>=6.0.2,<7