dycw-actions 0.3.2__py3-none-any.whl → 0.7.1__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.
Files changed (83) hide show
  1. actions/__init__.py +1 -1
  2. actions/action_dicts/constants.py +8 -0
  3. actions/action_dicts/lib.py +186 -0
  4. actions/clean_dir/cli.py +21 -0
  5. actions/clean_dir/constants.py +7 -0
  6. actions/clean_dir/lib.py +59 -0
  7. actions/clean_dir/settings.py +18 -0
  8. actions/cli.py +95 -6
  9. actions/constants.py +10 -0
  10. actions/pre_commit/click.py +15 -0
  11. actions/pre_commit/conformalize_repo/__init__.py +1 -0
  12. actions/pre_commit/conformalize_repo/cli.py +64 -0
  13. actions/pre_commit/conformalize_repo/configs/gitignore +244 -0
  14. actions/pre_commit/conformalize_repo/constants.py +78 -0
  15. actions/pre_commit/conformalize_repo/lib.py +1293 -0
  16. actions/pre_commit/conformalize_repo/settings.py +119 -0
  17. actions/pre_commit/constants.py +8 -0
  18. actions/pre_commit/format_requirements/__init__.py +1 -0
  19. actions/pre_commit/format_requirements/cli.py +24 -0
  20. actions/pre_commit/format_requirements/constants.py +7 -0
  21. actions/pre_commit/format_requirements/lib.py +52 -0
  22. actions/pre_commit/replace_sequence_strs/__init__.py +1 -0
  23. actions/pre_commit/replace_sequence_strs/cli.py +24 -0
  24. actions/pre_commit/replace_sequence_strs/constants.py +7 -0
  25. actions/pre_commit/replace_sequence_strs/lib.py +73 -0
  26. actions/pre_commit/touch_empty_py/__init__.py +1 -0
  27. actions/pre_commit/touch_empty_py/cli.py +24 -0
  28. actions/pre_commit/touch_empty_py/constants.py +7 -0
  29. actions/pre_commit/touch_empty_py/lib.py +54 -0
  30. actions/pre_commit/touch_py_typed/__init__.py +1 -0
  31. actions/pre_commit/touch_py_typed/cli.py +24 -0
  32. actions/pre_commit/touch_py_typed/constants.py +7 -0
  33. actions/pre_commit/touch_py_typed/lib.py +64 -0
  34. actions/pre_commit/update_requirements/__init__.py +1 -0
  35. actions/pre_commit/update_requirements/classes.py +117 -0
  36. actions/pre_commit/update_requirements/cli.py +24 -0
  37. actions/pre_commit/update_requirements/constants.py +7 -0
  38. actions/pre_commit/update_requirements/lib.py +128 -0
  39. actions/pre_commit/utilities.py +386 -0
  40. actions/publish_package/__init__.py +1 -0
  41. actions/publish_package/cli.py +27 -0
  42. actions/publish_package/constants.py +7 -0
  43. actions/{publish → publish_package}/lib.py +18 -17
  44. actions/{publish → publish_package}/settings.py +7 -7
  45. actions/py.typed +0 -0
  46. actions/random_sleep/__init__.py +1 -0
  47. actions/random_sleep/cli.py +26 -0
  48. actions/random_sleep/constants.py +7 -0
  49. actions/{sleep → random_sleep}/lib.py +14 -13
  50. actions/{sleep → random_sleep}/settings.py +3 -3
  51. actions/run_hooks/__init__.py +1 -0
  52. actions/run_hooks/cli.py +21 -0
  53. actions/run_hooks/constants.py +7 -0
  54. actions/run_hooks/lib.py +97 -0
  55. actions/run_hooks/settings.py +24 -0
  56. actions/setup_cronjob/__init__.py +1 -0
  57. actions/setup_cronjob/cli.py +31 -0
  58. actions/setup_cronjob/configs/cron.tmpl +3 -0
  59. actions/setup_cronjob/configs/logrotate.tmpl +10 -0
  60. actions/setup_cronjob/constants.py +12 -0
  61. actions/setup_cronjob/lib.py +120 -0
  62. actions/setup_cronjob/settings.py +27 -0
  63. actions/tag_commit/__init__.py +1 -0
  64. actions/tag_commit/cli.py +27 -0
  65. actions/tag_commit/constants.py +7 -0
  66. actions/tag_commit/lib.py +63 -0
  67. actions/{tag → tag_commit}/settings.py +3 -3
  68. actions/types.py +14 -1
  69. actions/utilities.py +131 -17
  70. dycw_actions-0.7.1.dist-info/METADATA +22 -0
  71. dycw_actions-0.7.1.dist-info/RECORD +77 -0
  72. {dycw_actions-0.3.2.dist-info → dycw_actions-0.7.1.dist-info}/WHEEL +1 -1
  73. actions/publish/cli.py +0 -43
  74. actions/settings.py +0 -18
  75. actions/sleep/cli.py +0 -39
  76. actions/tag/cli.py +0 -43
  77. actions/tag/lib.py +0 -62
  78. dycw_actions-0.3.2.dist-info/METADATA +0 -14
  79. dycw_actions-0.3.2.dist-info/RECORD +0 -22
  80. /actions/{publish → action_dicts}/__init__.py +0 -0
  81. /actions/{sleep → clean_dir}/__init__.py +0 -0
  82. /actions/{tag → pre_commit}/__init__.py +0 -0
  83. {dycw_actions-0.3.2.dist-info → dycw_actions-0.7.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,128 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from functools import partial
5
+ from typing import TYPE_CHECKING
6
+
7
+ from pydantic import TypeAdapter
8
+ from utilities.text import repr_str, strip_and_dedent
9
+
10
+ from actions import __version__
11
+ from actions.logging import LOGGER
12
+ from actions.pre_commit.update_requirements.classes import (
13
+ PipListOutdatedOutput,
14
+ Version1or2,
15
+ Version2,
16
+ Version3,
17
+ parse_version1_or_2,
18
+ parse_version2_or_3,
19
+ )
20
+ from actions.pre_commit.utilities import get_pyproject_dependencies, yield_toml_doc
21
+ from actions.utilities import logged_run
22
+
23
+ if TYPE_CHECKING:
24
+ from collections.abc import MutableSet
25
+ from pathlib import Path
26
+
27
+ from utilities.packaging import Requirement
28
+ from utilities.types import PathLike
29
+
30
+ from actions.pre_commit.update_requirements.classes import Version2or3, VersionSet
31
+
32
+
33
+ def update_requirements(*paths: PathLike) -> None:
34
+ LOGGER.info(
35
+ strip_and_dedent("""
36
+ Running '%s' (version %s) with settings:
37
+ - paths = %s
38
+ """),
39
+ update_requirements.__name__,
40
+ __version__,
41
+ paths,
42
+ )
43
+ modifications: set[Path] = set()
44
+ for path in paths:
45
+ _format_path(path, modifications=modifications)
46
+ if len(modifications) >= 1:
47
+ LOGGER.info(
48
+ "Exiting due to modifications: %s",
49
+ ", ".join(map(repr_str, sorted(modifications))),
50
+ )
51
+ sys.exit(1)
52
+
53
+
54
+ def _format_path(
55
+ path: PathLike,
56
+ /,
57
+ *,
58
+ versions: VersionSet | None = None,
59
+ modifications: MutableSet[Path] | None = None,
60
+ ) -> None:
61
+ versions_use = _get_versions() if versions is None else versions
62
+ with yield_toml_doc(path, modifications=modifications) as doc:
63
+ get_pyproject_dependencies(doc).apply(
64
+ partial(_format_req, versions=versions_use)
65
+ )
66
+
67
+
68
+ def _get_versions() -> VersionSet:
69
+ json = logged_run(
70
+ "uv", "pip", "list", "--format", "json", "--outdated", "--strict", return_=True
71
+ )
72
+ packages = TypeAdapter(list[PipListOutdatedOutput]).validate_json(json)
73
+ return {p.name: parse_version2_or_3(p.latest_version) for p in packages}
74
+
75
+
76
+ def _format_req(requirement: Requirement, /, *, versions: VersionSet) -> Requirement:
77
+ try:
78
+ lower = parse_version2_or_3(requirement[">="])
79
+ except KeyError:
80
+ lower = None
81
+ try:
82
+ upper = parse_version1_or_2(requirement["<"])
83
+ except KeyError:
84
+ upper = None
85
+ latest = versions.get(requirement.name)
86
+ new_lower: Version2or3 | None = None
87
+ new_upper: Version1or2 | None = None
88
+ match lower, upper, latest:
89
+ case None, None, None:
90
+ ...
91
+ case None, None, Version2() | Version3():
92
+ new_lower = latest
93
+ new_upper = latest.bump_major().major
94
+ case Version2() | Version3(), None, None:
95
+ new_lower = lower
96
+ case (Version2(), None, Version2()) | (Version3(), None, Version3()):
97
+ new_lower = max(lower, latest)
98
+ case None, int() | Version2(), None:
99
+ new_upper = upper
100
+ case None, int(), Version2():
101
+ new_upper = max(upper, latest.bump_major().major)
102
+ case None, Version2(), Version3():
103
+ bumped = latest.bump_minor()
104
+ new_upper = max(upper, Version2(bumped.major, bumped.minor))
105
+ case (
106
+ (Version2(), int(), None)
107
+ | (Version3(), int(), None)
108
+ | (Version3(), Version2(), None)
109
+ ):
110
+ new_lower = lower
111
+ new_upper = lower.bump_major().major
112
+ case (
113
+ (Version2(), int(), Version2())
114
+ | (Version3(), int(), Version3())
115
+ | (Version3(), Version2(), Version3())
116
+ ):
117
+ new_lower = max(lower, latest)
118
+ new_upper = new_lower.bump_major().major
119
+ case never:
120
+ raise NotImplementedError(never)
121
+ if new_lower is not None:
122
+ requirement = requirement.replace(">=", str(new_lower))
123
+ if new_upper is not None:
124
+ requirement = requirement.replace("<", str(new_upper))
125
+ return requirement
126
+
127
+
128
+ __all__ = ["update_requirements"]
@@ -0,0 +1,386 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from collections.abc import Iterator, MutableSet
5
+ from contextlib import contextmanager
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import TYPE_CHECKING, Any, assert_never
9
+
10
+ import tomlkit
11
+ from libcst import Module, parse_module
12
+ from rich.pretty import pretty_repr
13
+ from tomlkit import TOMLDocument, aot, array, document, string, table
14
+ from tomlkit.items import AoT, Array, Table
15
+ from utilities.functions import ensure_class, ensure_str
16
+ from utilities.iterables import OneEmptyError, OneNonUniqueError, one
17
+ from utilities.packaging import Requirement
18
+ from utilities.types import PathLike
19
+
20
+ from actions.constants import YAML_INSTANCE
21
+ from actions.logging import LOGGER
22
+ from actions.types import StrDict
23
+ from actions.utilities import are_equal_modulo_new_line, write_text, yaml_dump
24
+
25
+ if TYPE_CHECKING:
26
+ from collections.abc import Callable, Iterable, Iterator, MutableSet
27
+
28
+ from utilities.types import PathLike
29
+
30
+ from actions.types import FuncRequirement, HasAppend, HasSetDefault, StrDict
31
+
32
+
33
+ def ensure_aot_contains(array: AoT, /, *tables: Table) -> None:
34
+ for table_ in tables:
35
+ if table_ not in array:
36
+ array.append(table_)
37
+
38
+
39
+ def ensure_contains(array: HasAppend, /, *objs: Any) -> None:
40
+ if isinstance(array, AoT):
41
+ msg = f"Use {ensure_aot_contains.__name__!r} instead of {ensure_contains.__name__!r}"
42
+ raise TypeError(msg)
43
+ for obj in objs:
44
+ if obj not in array:
45
+ array.append(obj)
46
+
47
+
48
+ def ensure_contains_partial_dict(
49
+ container: HasAppend, partial: StrDict, /, *, extra: StrDict | None = None
50
+ ) -> StrDict:
51
+ try:
52
+ return get_partial_dict(container, partial, skip_log=True)
53
+ except OneEmptyError:
54
+ dict_ = partial | ({} if extra is None else extra)
55
+ container.append(dict_)
56
+ return dict_
57
+
58
+
59
+ def ensure_contains_partial_str(container: HasAppend, text: str, /) -> str:
60
+ try:
61
+ return get_partial_str(container, text, skip_log=True)
62
+ except OneEmptyError:
63
+ container.append(text)
64
+ return text
65
+
66
+
67
+ def ensure_not_contains(array: Array, /, *objs: Any) -> None:
68
+ for obj in objs:
69
+ try:
70
+ index = next(i for i, o in enumerate(array) if o == obj)
71
+ except StopIteration:
72
+ pass
73
+ else:
74
+ del array[index]
75
+
76
+
77
+ ##
78
+
79
+
80
+ def get_aot(container: HasSetDefault, key: str, /) -> AoT:
81
+ return ensure_class(container.setdefault(key, aot()), AoT)
82
+
83
+
84
+ def get_array(container: HasSetDefault, key: str, /) -> Array:
85
+ return ensure_class(container.setdefault(key, array()), Array)
86
+
87
+
88
+ def get_dict(container: HasSetDefault, key: str, /) -> StrDict:
89
+ return ensure_class(container.setdefault(key, {}), dict)
90
+
91
+
92
+ def get_list(container: HasSetDefault, key: str, /) -> list[Any]:
93
+ return ensure_class(container.setdefault(key, []), list)
94
+
95
+
96
+ def get_table(container: HasSetDefault, key: str, /) -> Table:
97
+ return ensure_class(container.setdefault(key, table()), Table)
98
+
99
+
100
+ ##
101
+
102
+
103
+ def get_partial_dict(
104
+ iterable: Iterable[Any], dict_: StrDict, /, *, skip_log: bool = False
105
+ ) -> StrDict:
106
+ try:
107
+ return one(i for i in iterable if is_partial_dict(dict_, i))
108
+ except OneEmptyError:
109
+ if not skip_log:
110
+ LOGGER.exception(
111
+ "Expected %s to contain %s (as a partial)",
112
+ pretty_repr(iterable),
113
+ pretty_repr(dict_),
114
+ )
115
+ raise
116
+ except OneNonUniqueError as error:
117
+ LOGGER.exception(
118
+ "Expected %s to contain %s uniquely (as a partial); got %s, %s and perhaps more",
119
+ pretty_repr(iterable),
120
+ pretty_repr(dict_),
121
+ pretty_repr(error.first),
122
+ pretty_repr(error.second),
123
+ )
124
+ raise
125
+
126
+
127
+ def is_partial_dict(obj: Any, dict_: StrDict, /) -> bool:
128
+ if not isinstance(obj, dict):
129
+ return False
130
+ results: dict[str, bool] = {}
131
+ for key, obj_value in obj.items():
132
+ try:
133
+ dict_value = dict_[key]
134
+ except KeyError:
135
+ results[key] = False
136
+ else:
137
+ if isinstance(obj_value, dict) and isinstance(dict_value, dict):
138
+ results[key] = is_partial_dict(obj_value, dict_value)
139
+ else:
140
+ results[key] = obj_value == dict_value
141
+ return all(results.values())
142
+
143
+
144
+ ##
145
+
146
+
147
+ def get_partial_str(
148
+ iterable: Iterable[Any], text: str, /, *, skip_log: bool = False
149
+ ) -> str:
150
+ try:
151
+ return one(i for i in iterable if is_partial_str(i, text))
152
+ except OneEmptyError:
153
+ if not skip_log:
154
+ LOGGER.exception(
155
+ "Expected %s to contain %s (as a partial)",
156
+ pretty_repr(iterable),
157
+ pretty_repr(text),
158
+ )
159
+ raise
160
+ except OneNonUniqueError as error:
161
+ LOGGER.exception(
162
+ "Expected %s to contain %s uniquely (as a partial); got %s, %s and perhaps more",
163
+ pretty_repr(iterable),
164
+ pretty_repr(text),
165
+ pretty_repr(error.first),
166
+ pretty_repr(error.second),
167
+ )
168
+ raise
169
+
170
+
171
+ def is_partial_str(obj: Any, text: str, /) -> bool:
172
+ return isinstance(obj, str) and (text in obj)
173
+
174
+
175
+ ##
176
+
177
+
178
+ def get_pyproject_dependencies(doc: TOMLDocument, /) -> PyProjectDependencies:
179
+ out = PyProjectDependencies()
180
+ if (project_key := "project") in doc:
181
+ project = get_table(doc, project_key)
182
+ if (dep_key := "dependencies") in project:
183
+ out.dependencies = get_array(project, dep_key)
184
+ if (opt_dep_key := "optional-dependencies") in project:
185
+ opt_dependencies = get_table(project, opt_dep_key)
186
+ out.opt_dependencies = {}
187
+ for key in opt_dependencies:
188
+ out.opt_dependencies[ensure_str(key)] = get_array(opt_dependencies, key)
189
+ if (dep_grps_key := "dependency-groups") in doc:
190
+ dep_grps = get_table(doc, dep_grps_key)
191
+ out.dep_groups = {}
192
+ for key in dep_grps:
193
+ out.dep_groups[ensure_str(key)] = get_array(dep_grps, key)
194
+ return out
195
+
196
+
197
+ @dataclass(kw_only=True, slots=True)
198
+ class PyProjectDependencies:
199
+ dependencies: Array | None = None
200
+ opt_dependencies: dict[str, Array] | None = None
201
+ dep_groups: dict[str, Array] | None = None
202
+
203
+ def apply(self, func: FuncRequirement, /) -> None:
204
+ if (deps := self.dependencies) is not None:
205
+ self._apply_to_array(deps, func)
206
+ if (opt_depedencies := self.opt_dependencies) is not None:
207
+ for deps in opt_depedencies.values():
208
+ self._apply_to_array(deps, func)
209
+ if (dep_grps := self.dep_groups) is not None:
210
+ for deps in dep_grps.values():
211
+ self._apply_to_array(deps, func)
212
+
213
+ def _apply_to_array(self, array: Array, func: FuncRequirement, /) -> None:
214
+ strs = list(map(ensure_str, array))
215
+ reqs = list(map(Requirement, strs))
216
+ results = list(map(func, reqs))
217
+ new_strs = list(map(str, results))
218
+ strings = list(map(string, new_strs))
219
+ array.clear()
220
+ ensure_contains(array, *strings)
221
+
222
+
223
+ ##
224
+
225
+
226
+ @contextmanager
227
+ def yield_json_dict(
228
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
229
+ ) -> Iterator[StrDict]:
230
+ with yield_mutable_write_context(
231
+ path, json.loads, dict, json.dumps, modifications=modifications
232
+ ) as dict_:
233
+ yield dict_
234
+
235
+
236
+ ##
237
+
238
+
239
+ @contextmanager
240
+ def yield_python_file(
241
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
242
+ ) -> Iterator[WriteContext[Module]]:
243
+ with yield_immutable_write_context(
244
+ path,
245
+ parse_module,
246
+ lambda: Module(body=[]),
247
+ lambda module: module.code,
248
+ modifications=modifications,
249
+ ) as context:
250
+ yield context
251
+
252
+
253
+ ##
254
+
255
+
256
+ @contextmanager
257
+ def yield_text_file(
258
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
259
+ ) -> Iterator[WriteContext[str]]:
260
+ with yield_immutable_write_context(
261
+ path, str, lambda: "", str, modifications=modifications
262
+ ) as context:
263
+ yield context
264
+
265
+
266
+ ##
267
+
268
+
269
+ @contextmanager
270
+ def yield_toml_doc(
271
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
272
+ ) -> Iterator[TOMLDocument]:
273
+ with yield_mutable_write_context(
274
+ path, tomlkit.parse, document, tomlkit.dumps, modifications=modifications
275
+ ) as doc:
276
+ yield doc
277
+
278
+
279
+ ##
280
+
281
+
282
+ @contextmanager
283
+ def yield_mutable_write_context[T](
284
+ path: PathLike,
285
+ loads: Callable[[str], T],
286
+ get_default: Callable[[], T],
287
+ dumps: Callable[[T], str],
288
+ /,
289
+ *,
290
+ modifications: MutableSet[Path] | None = None,
291
+ ) -> Iterator[T]:
292
+ with yield_immutable_write_context(
293
+ path, loads, get_default, dumps, modifications=modifications
294
+ ) as context:
295
+ yield context.output
296
+
297
+
298
+ ##
299
+
300
+
301
+ @dataclass(kw_only=True, slots=True)
302
+ class WriteContext[T]:
303
+ input: T
304
+ output: T
305
+
306
+
307
+ @contextmanager
308
+ def yield_immutable_write_context[T](
309
+ path: PathLike,
310
+ loads: Callable[[str], T],
311
+ get_default: Callable[[], T],
312
+ dumps: Callable[[T], str],
313
+ /,
314
+ *,
315
+ modifications: MutableSet[Path] | None = None,
316
+ ) -> Iterator[WriteContext[T]]:
317
+ try:
318
+ current = Path(path).read_text()
319
+ except FileNotFoundError:
320
+ current = None
321
+ input_ = get_default()
322
+ output = get_default()
323
+ else:
324
+ input_ = loads(current)
325
+ output = loads(current)
326
+ yield (context := WriteContext(input=input_, output=output))
327
+ if current is None:
328
+ write_text(path, dumps(context.output), modifications=modifications)
329
+ else:
330
+ match context.output, loads(current):
331
+ case Module() as output_module, Module() as current_module:
332
+ if not are_equal_modulo_new_line(
333
+ output_module.code, current_module.code
334
+ ):
335
+ write_text(path, dumps(output_module), modifications=modifications)
336
+ case TOMLDocument() as output_doc, TOMLDocument() as current_doc:
337
+ if not (output_doc == current_doc): # noqa: SIM201
338
+ write_text(path, dumps(output_doc), modifications=modifications)
339
+ case str() as output_text, str() as current_text:
340
+ if not are_equal_modulo_new_line(output_text, current_text):
341
+ write_text(path, dumps(output_text), modifications=modifications)
342
+ case output_obj, current_obj:
343
+ if output_obj != current_obj:
344
+ write_text(path, dumps(output_obj), modifications=modifications)
345
+ case never:
346
+ assert_never(never)
347
+
348
+
349
+ ##
350
+
351
+
352
+ @contextmanager
353
+ def yield_yaml_dict(
354
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
355
+ ) -> Iterator[StrDict]:
356
+ with yield_mutable_write_context(
357
+ path, YAML_INSTANCE.load, dict, yaml_dump, modifications=modifications
358
+ ) as dict_:
359
+ yield dict_
360
+
361
+
362
+ __all__ = [
363
+ "PyProjectDependencies",
364
+ "ensure_aot_contains",
365
+ "ensure_contains",
366
+ "ensure_contains_partial_dict",
367
+ "ensure_contains_partial_str",
368
+ "ensure_not_contains",
369
+ "get_aot",
370
+ "get_array",
371
+ "get_dict",
372
+ "get_list",
373
+ "get_partial_dict",
374
+ "get_partial_str",
375
+ "get_pyproject_dependencies",
376
+ "get_table",
377
+ "is_partial_dict",
378
+ "is_partial_str",
379
+ "yield_immutable_write_context",
380
+ "yield_json_dict",
381
+ "yield_mutable_write_context",
382
+ "yield_python_file",
383
+ "yield_text_file",
384
+ "yield_toml_doc",
385
+ "yield_yaml_dict",
386
+ ]
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ from typed_settings import click_options
4
+ from utilities.logging import basic_config
5
+ from utilities.os import is_pytest
6
+
7
+ from actions.logging import LOGGER
8
+ from actions.publish_package.lib import publish_package
9
+ from actions.publish_package.settings import Settings
10
+ from actions.utilities import LOADER
11
+
12
+
13
+ @click_options(Settings, [LOADER], show_envvars_in_help=True)
14
+ def publish_package_sub_cmd(settings: Settings, /) -> None:
15
+ if is_pytest():
16
+ return
17
+ basic_config(obj=LOGGER)
18
+ publish_package(
19
+ username=settings.username,
20
+ password=settings.password,
21
+ publish_url=settings.publish_url,
22
+ trusted_publishing=settings.trusted_publishing,
23
+ native_tls=settings.native_tls,
24
+ )
25
+
26
+
27
+ __all__ = ["publish_package_sub_cmd"]
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ PUBLISH_PACKAGE_DOCSTRING = "Build and publish the package"
4
+ PUBLISH_PACKAGE_SUB_CMD = "publish-package"
5
+
6
+
7
+ __all__ = ["PUBLISH_PACKAGE_DOCSTRING", "PUBLISH_PACKAGE_SUB_CMD"]
@@ -3,11 +3,12 @@ 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
6
7
 
7
8
  from actions import __version__
8
9
  from actions.logging import LOGGER
9
- from actions.publish.settings import PUBLISH_SETTINGS
10
- from actions.utilities import log_run
10
+ from actions.publish_package.settings import SETTINGS
11
+ from actions.utilities import logged_run
11
12
 
12
13
  if TYPE_CHECKING:
13
14
  from typed_settings import Secret
@@ -15,21 +16,21 @@ if TYPE_CHECKING:
15
16
 
16
17
  def publish_package(
17
18
  *,
18
- username: str | None = PUBLISH_SETTINGS.username,
19
- password: Secret[str] | None = PUBLISH_SETTINGS.password,
20
- publish_url: str | None = PUBLISH_SETTINGS.publish_url,
21
- trusted_publishing: bool = PUBLISH_SETTINGS.trusted_publishing,
22
- native_tls: bool = PUBLISH_SETTINGS.native_tls,
19
+ username: str | None = SETTINGS.username,
20
+ password: Secret[str] | None = SETTINGS.password,
21
+ publish_url: str | None = SETTINGS.publish_url,
22
+ trusted_publishing: bool = SETTINGS.trusted_publishing,
23
+ native_tls: bool = SETTINGS.native_tls,
23
24
  ) -> None:
24
25
  LOGGER.info(
25
- """\
26
- Running %r (version %s) with settings:
27
- - username = %s
28
- - password = %s
29
- - publish_url = %s
30
- - trusted_publishing = %s
31
- - native_tls = %s
32
- """,
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
+ """),
33
34
  publish_package.__name__,
34
35
  __version__,
35
36
  username,
@@ -39,8 +40,8 @@ Running %r (version %s) with settings:
39
40
  native_tls,
40
41
  )
41
42
  with TemporaryDirectory() as temp:
42
- _ = log_run("uv", "build", "--out-dir", str(temp), "--wheel", "--clear")
43
- _ = log_run(
43
+ logged_run("uv", "build", "--out-dir", str(temp), "--wheel", "--clear")
44
+ logged_run(
44
45
  "uv",
45
46
  "publish",
46
47
  *([] if username is None else ["--username", username]),
@@ -2,19 +2,19 @@ from __future__ import annotations
2
2
 
3
3
  from typed_settings import Secret, load_settings, option, secret, settings
4
4
 
5
- from actions.utilities import LOADER, empty_str_to_none
5
+ from actions.utilities import LOADER, convert_secret_str, convert_str
6
6
 
7
7
 
8
8
  @settings
9
- class PublishSettings:
9
+ class Settings:
10
10
  username: str | None = option(
11
- default=None, converter=empty_str_to_none, help="The username of the upload"
11
+ default=None, converter=convert_str, help="The username of the upload"
12
12
  )
13
13
  password: Secret[str] | None = secret(
14
- default=None, converter=empty_str_to_none, help="The password for the upload"
14
+ default=None, converter=convert_secret_str, help="The password for the upload"
15
15
  )
16
16
  publish_url: str | None = option(
17
- default=None, converter=empty_str_to_none, help="The URL of the upload endpoint"
17
+ default=None, converter=convert_str, help="The URL of the upload endpoint"
18
18
  )
19
19
  trusted_publishing: bool = option(
20
20
  default=False, help="Configure trusted publishing"
@@ -25,7 +25,7 @@ class PublishSettings:
25
25
  )
26
26
 
27
27
 
28
- PUBLISH_SETTINGS = load_settings(PublishSettings, [LOADER])
28
+ SETTINGS = load_settings(Settings, [LOADER])
29
29
 
30
30
 
31
- __all__ = ["PUBLISH_SETTINGS", "PublishSettings"]
31
+ __all__ = ["SETTINGS", "Settings"]
actions/py.typed ADDED
File without changes
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ from typed_settings import click_options
4
+ from utilities.logging import basic_config
5
+ from utilities.os import is_pytest
6
+
7
+ from actions.logging import LOGGER
8
+ from actions.random_sleep.lib import random_sleep
9
+ from actions.random_sleep.settings import Settings
10
+ from actions.utilities import LOADER
11
+
12
+
13
+ @click_options(Settings, [LOADER], show_envvars_in_help=True)
14
+ def random_sleep_sub_cmd(settings: Settings, /) -> None:
15
+ if is_pytest():
16
+ return
17
+ basic_config(obj=LOGGER)
18
+ random_sleep(
19
+ min_=settings.min,
20
+ max_=settings.max,
21
+ step=settings.step,
22
+ log_freq=settings.log_freq,
23
+ )
24
+
25
+
26
+ __all__ = ["random_sleep_sub_cmd"]
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ RANDOM_SLEEP_DOCSTRING = "Random sleep with logging"
4
+ RANDOM_SLEEP_SUB_CMD = "random-sleep"
5
+
6
+
7
+ __all__ = ["RANDOM_SLEEP_DOCSTRING", "RANDOM_SLEEP_SUB_CMD"]