dycw-actions 0.8.11__py3-none-any.whl → 0.14.0__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 (46) hide show
  1. actions/.DS_Store +0 -0
  2. actions/__init__.py +1 -1
  3. actions/clean_dir/lib.py +7 -4
  4. actions/cli.py +23 -2
  5. actions/constants.py +2 -0
  6. actions/git_clone_with/__init__.py +1 -0
  7. actions/git_clone_with/cli.py +41 -0
  8. actions/git_clone_with/constants.py +7 -0
  9. actions/git_clone_with/lib.py +78 -0
  10. actions/git_clone_with/settings.py +20 -0
  11. actions/pre_commit/conformalize_repo/action_dicts.py +39 -40
  12. actions/pre_commit/conformalize_repo/cli.py +16 -4
  13. actions/pre_commit/conformalize_repo/constants.py +14 -0
  14. actions/pre_commit/conformalize_repo/lib.py +350 -220
  15. actions/pre_commit/conformalize_repo/settings.py +42 -16
  16. actions/pre_commit/constants.py +3 -3
  17. actions/pre_commit/format_requirements/lib.py +5 -2
  18. actions/pre_commit/replace_sequence_strs/lib.py +5 -2
  19. actions/pre_commit/touch_empty_py/lib.py +7 -4
  20. actions/pre_commit/touch_py_typed/lib.py +9 -5
  21. actions/pre_commit/update_requirements/cli.py +10 -2
  22. actions/pre_commit/update_requirements/lib.py +78 -15
  23. actions/pre_commit/update_requirements/settings.py +23 -0
  24. actions/pre_commit/utilities.py +131 -39
  25. actions/publish_package/lib.py +33 -20
  26. actions/random_sleep/lib.py +12 -7
  27. actions/re_encrypt/__init__.py +1 -0
  28. actions/re_encrypt/cli.py +36 -0
  29. actions/re_encrypt/constants.py +7 -0
  30. actions/re_encrypt/lib.py +115 -0
  31. actions/re_encrypt/settings.py +26 -0
  32. actions/register_gitea_runner/configs/entrypoint.sh +8 -8
  33. actions/register_gitea_runner/lib.py +23 -14
  34. actions/run_hooks/lib.py +27 -14
  35. actions/setup_cronjob/lib.py +19 -13
  36. actions/setup_ssh_config/__init__.py +1 -0
  37. actions/setup_ssh_config/cli.py +17 -0
  38. actions/setup_ssh_config/constants.py +7 -0
  39. actions/setup_ssh_config/lib.py +30 -0
  40. actions/tag_commit/lib.py +16 -9
  41. actions/types.py +5 -9
  42. actions/utilities.py +1 -16
  43. {dycw_actions-0.8.11.dist-info → dycw_actions-0.14.0.dist-info}/METADATA +5 -3
  44. {dycw_actions-0.8.11.dist-info → dycw_actions-0.14.0.dist-info}/RECORD +46 -30
  45. {dycw_actions-0.8.11.dist-info → dycw_actions-0.14.0.dist-info}/WHEEL +1 -1
  46. {dycw_actions-0.8.11.dist-info → dycw_actions-0.14.0.dist-info}/entry_points.txt +0 -0
@@ -14,13 +14,16 @@ from typing import TYPE_CHECKING, Literal, assert_never
14
14
  import tomlkit
15
15
  from tomlkit import TOMLDocument, table
16
16
  from tomlkit.exceptions import NonExistentKey
17
+ from utilities.functions import get_func_name
17
18
  from utilities.inflect import counted_noun
18
19
  from utilities.re import extract_groups
19
20
  from utilities.subprocess import ripgrep
21
+ from utilities.tabulate import func_param_desc
20
22
  from utilities.text import repr_str, strip_and_dedent
21
23
  from utilities.throttle import throttle
22
24
  from utilities.version import ParseVersionError, Version, parse_version
23
25
 
26
+ from actions import __version__
24
27
  from actions.constants import (
25
28
  ACTIONS_URL,
26
29
  BUMPVERSION_TOML,
@@ -28,6 +31,7 @@ from actions.constants import (
28
31
  ENVRC,
29
32
  GITEA_PULL_REQUEST_YAML,
30
33
  GITEA_PUSH_YAML,
34
+ GITHUB,
31
35
  GITHUB_PULL_REQUEST_YAML,
32
36
  GITHUB_PUSH_YAML,
33
37
  GITIGNORE,
@@ -62,7 +66,7 @@ from actions.pre_commit.conformalize_repo.constants import (
62
66
  UV_URL,
63
67
  )
64
68
  from actions.pre_commit.conformalize_repo.settings import SETTINGS
65
- from actions.pre_commit.constants import THROTTLE_DELTA
69
+ from actions.pre_commit.constants import THROTTLE_DURATION
66
70
  from actions.pre_commit.format_requirements.constants import FORMAT_REQUIREMENTS_SUB_CMD
67
71
  from actions.pre_commit.replace_sequence_strs.constants import (
68
72
  REPLACE_SEQUENCE_STRS_SUB_CMD,
@@ -71,23 +75,24 @@ from actions.pre_commit.touch_empty_py.constants import TOUCH_EMPTY_PY_SUB_CMD
71
75
  from actions.pre_commit.touch_py_typed.constants import TOUCH_PY_TYPED_SUB_CMD
72
76
  from actions.pre_commit.update_requirements.constants import UPDATE_REQUIREMENTS_SUB_CMD
73
77
  from actions.pre_commit.utilities import (
74
- ensure_aot_contains,
75
78
  ensure_contains,
76
79
  ensure_contains_partial_dict,
77
80
  ensure_contains_partial_str,
78
81
  ensure_not_contains,
79
- get_aot,
80
- get_array,
81
- get_dict,
82
- get_list,
83
- get_table,
82
+ get_set_aot,
83
+ get_set_array,
84
+ get_set_dict,
85
+ get_set_list_dicts,
86
+ get_set_list_strs,
87
+ get_set_table,
84
88
  path_throttle_cache,
85
89
  yield_json_dict,
90
+ yield_pyproject_toml,
86
91
  yield_text_file,
87
92
  yield_toml_doc,
88
93
  yield_yaml_dict,
89
94
  )
90
- from actions.utilities import log_func_call, logged_run
95
+ from actions.utilities import logged_run
91
96
 
92
97
  if TYPE_CHECKING:
93
98
  from collections.abc import Iterator, MutableSet
@@ -99,9 +104,10 @@ if TYPE_CHECKING:
99
104
 
100
105
  def conformalize_repo(
101
106
  *,
102
- ci__ca_certificates: bool = SETTINGS.ci__ca_certificates,
107
+ ci__certificates: bool = SETTINGS.ci__certificates,
103
108
  ci__gitea: bool = SETTINGS.ci__gitea,
104
- ci__token: str | None = SETTINGS.ci__token,
109
+ ci__token_checkout: Secret[str] | None = SETTINGS.ci__token_checkout,
110
+ ci__token_github: Secret[str] | None = SETTINGS.ci__token_github,
105
111
  ci__pull_request__pre_commit: bool = SETTINGS.ci__pull_request__pre_commit,
106
112
  ci__pull_request__pre_commit__submodules: str
107
113
  | None = SETTINGS.ci__pull_request__pre_commit__submodules,
@@ -110,15 +116,26 @@ def conformalize_repo(
110
116
  ci__pull_request__pytest__ubuntu: bool = SETTINGS.ci__pull_request__pytest__ubuntu,
111
117
  ci__pull_request__pytest__windows: bool = SETTINGS.ci__pull_request__pytest__windows,
112
118
  ci__pull_request__pytest__all_versions: bool = SETTINGS.ci__pull_request__pytest__all_versions,
113
- ci__pull_request__pytest__sops_age_key: str
119
+ ci__pull_request__pytest__sops_age_key: Secret[str]
114
120
  | None = SETTINGS.ci__pull_request__pytest__sops_age_key,
115
121
  ci__pull_request__ruff: bool = SETTINGS.ci__pull_request__ruff,
116
- ci__push__publish: bool = SETTINGS.ci__push__publish,
117
- ci__push__publish__username: str | None = SETTINGS.ci__push__publish__username,
118
- ci__push__publish__password: Secret[str]
119
- | None = SETTINGS.ci__push__publish__password,
120
- ci__push__publish__publish_url: Secret[str]
121
- | None = SETTINGS.ci__push__publish__publish_url,
122
+ ci__push__publish__github: bool = SETTINGS.ci__push__publish__github,
123
+ ci__push__publish__primary: bool = SETTINGS.ci__push__publish__primary,
124
+ ci__push__publish__primary__job_name: str = SETTINGS.ci__push__publish__primary__job_name,
125
+ ci__push__publish__primary__username: str
126
+ | None = SETTINGS.ci__push__publish__primary__username,
127
+ ci__push__publish__primary__password: Secret[str]
128
+ | None = SETTINGS.ci__push__publish__primary__password,
129
+ ci__push__publish__primary__publish_url: str
130
+ | None = SETTINGS.ci__push__publish__primary__publish_url,
131
+ ci__push__publish__secondary: bool = SETTINGS.ci__push__publish__secondary,
132
+ ci__push__publish__secondary__job_name: str = SETTINGS.ci__push__publish__secondary__job_name,
133
+ ci__push__publish__secondary__username: str
134
+ | None = SETTINGS.ci__push__publish__secondary__username,
135
+ ci__push__publish__secondary__password: Secret[str]
136
+ | None = SETTINGS.ci__push__publish__secondary__password,
137
+ ci__push__publish__secondary__publish_url: str
138
+ | None = SETTINGS.ci__push__publish__secondary__publish_url,
122
139
  ci__push__tag: bool = SETTINGS.ci__push__tag,
123
140
  ci__push__tag__all: bool = SETTINGS.ci__push__tag__all,
124
141
  coverage: bool = SETTINGS.coverage,
@@ -136,9 +153,6 @@ def conformalize_repo(
136
153
  pre_commit__uv: bool = SETTINGS.pre_commit__uv,
137
154
  pyproject: bool = SETTINGS.pyproject,
138
155
  pyproject__project__optional_dependencies__scripts: bool = SETTINGS.pyproject__project__optional_dependencies__scripts,
139
- pyproject__tool__uv__indexes: list[
140
- tuple[str, str]
141
- ] = SETTINGS.pyproject__tool__uv__indexes,
142
156
  pyright: bool = SETTINGS.pyright,
143
157
  pytest: bool = SETTINGS.pytest,
144
158
  pytest__asyncio: bool = SETTINGS.pytest__asyncio,
@@ -151,58 +165,70 @@ def conformalize_repo(
151
165
  ruff: bool = SETTINGS.ruff,
152
166
  run_version_bump: bool = SETTINGS.run_version_bump,
153
167
  script: str | None = SETTINGS.script,
168
+ uv__indexes: list[tuple[str, str]] = SETTINGS.uv__indexes,
154
169
  uv__native_tls: bool = SETTINGS.uv__native_tls,
155
170
  ) -> None:
156
- variables = [
157
- f"{ci__ca_certificates=}",
158
- f"{ci__gitea=}",
159
- f"{ci__token=}",
160
- f"{ci__pull_request__pre_commit=}",
161
- f"{ci__pull_request__pre_commit__submodules=}",
162
- f"{ci__pull_request__pyright=}",
163
- f"{ci__pull_request__pytest__macos=}",
164
- f"{ci__pull_request__pytest__ubuntu=}",
165
- f"{ci__pull_request__pytest__windows=}",
166
- f"{ci__pull_request__pytest__all_versions=}",
167
- f"{ci__pull_request__pytest__sops_age_key=}",
168
- f"{ci__pull_request__ruff=}",
169
- f"{ci__push__publish=}",
170
- f"{ci__push__publish__username=}",
171
- f"{ci__push__publish__password=}",
172
- f"{ci__push__publish__publish_url=}",
173
- f"{ci__push__tag=}",
174
- f"{ci__push__tag__all=}",
175
- f"{coverage=}",
176
- f"{description=}",
177
- f"{envrc=}",
178
- f"{envrc__uv=}",
179
- f"{gitignore=}",
180
- f"{package_name=}",
181
- f"{pre_commit__dockerfmt=}",
182
- f"{pre_commit__prettier=}",
183
- f"{pre_commit__python=}",
184
- f"{pre_commit__ruff=}",
185
- f"{pre_commit__shell=}",
186
- f"{pre_commit__taplo=}",
187
- f"{pre_commit__uv=}",
188
- f"{pyproject=}",
189
- f"{pyproject__project__optional_dependencies__scripts=}",
190
- f"{pyproject__tool__uv__indexes=}",
191
- f"{pyright=}",
192
- f"{pytest=}",
193
- f"{pytest__asyncio=}",
194
- f"{pytest__ignore_warnings=}",
195
- f"{pytest__timeout=}",
196
- f"{python_package_name=}",
197
- f"{python_version=}",
198
- f"{readme=}",
199
- f"{repo_name=}",
200
- f"{ruff=}",
201
- f"{run_version_bump=}",
202
- f"{script=}",
203
- f"{uv__native_tls=}",
204
- ]
205
- LOGGER.info(log_func_call(conformalize_repo, *variables))
171
+ LOGGER.info(
172
+ func_param_desc(
173
+ conformalize_repo,
174
+ __version__,
175
+ f"{ci__certificates=}",
176
+ f"{ci__gitea=}",
177
+ f"{ci__token_checkout=}",
178
+ f"{ci__token_github=}",
179
+ f"{ci__pull_request__pre_commit=}",
180
+ f"{ci__pull_request__pre_commit__submodules=}",
181
+ f"{ci__pull_request__pyright=}",
182
+ f"{ci__pull_request__pytest__macos=}",
183
+ f"{ci__pull_request__pytest__ubuntu=}",
184
+ f"{ci__pull_request__pytest__windows=}",
185
+ f"{ci__pull_request__pytest__all_versions=}",
186
+ f"{ci__pull_request__pytest__sops_age_key=}",
187
+ f"{ci__pull_request__ruff=}",
188
+ f"{ci__push__publish__github=}",
189
+ f"{ci__push__publish__primary=}",
190
+ f"{ci__push__publish__primary__job_name=}",
191
+ f"{ci__push__publish__primary__username=}",
192
+ f"{ci__push__publish__primary__password=}",
193
+ f"{ci__push__publish__primary__publish_url=}",
194
+ f"{ci__push__publish__secondary=}",
195
+ f"{ci__push__publish__secondary__job_name=}",
196
+ f"{ci__push__publish__secondary__username=}",
197
+ f"{ci__push__publish__secondary__password=}",
198
+ f"{ci__push__publish__secondary__publish_url=}",
199
+ f"{ci__push__tag=}",
200
+ f"{ci__push__tag__all=}",
201
+ f"{coverage=}",
202
+ f"{description=}",
203
+ f"{envrc=}",
204
+ f"{envrc__uv=}",
205
+ f"{gitignore=}",
206
+ f"{package_name=}",
207
+ f"{pre_commit__dockerfmt=}",
208
+ f"{pre_commit__prettier=}",
209
+ f"{pre_commit__python=}",
210
+ f"{pre_commit__ruff=}",
211
+ f"{pre_commit__shell=}",
212
+ f"{pre_commit__taplo=}",
213
+ f"{pre_commit__uv=}",
214
+ f"{pyproject=}",
215
+ f"{pyproject__project__optional_dependencies__scripts=}",
216
+ f"{pyright=}",
217
+ f"{pytest=}",
218
+ f"{pytest__asyncio=}",
219
+ f"{pytest__ignore_warnings=}",
220
+ f"{pytest__timeout=}",
221
+ f"{python_package_name=}",
222
+ f"{python_version=}",
223
+ f"{readme=}",
224
+ f"{repo_name=}",
225
+ f"{ruff=}",
226
+ f"{run_version_bump=}",
227
+ f"{script=}",
228
+ f"{uv__indexes=}",
229
+ f"{uv__native_tls=}",
230
+ )
231
+ )
206
232
  modifications: set[Path] = set()
207
233
  add_bumpversion_toml(
208
234
  modifications=modifications,
@@ -225,55 +251,70 @@ def conformalize_repo(
225
251
  taplo=pre_commit__taplo,
226
252
  uv=pre_commit__uv,
227
253
  script=script,
254
+ uv__indexes=uv__indexes,
255
+ uv__native_tls=uv__native_tls,
228
256
  )
229
257
  if (
230
258
  ci__pull_request__pre_commit
231
- or ci__pull_request__pre_commit__submodules
232
259
  or ci__pull_request__pyright
233
260
  or ci__pull_request__pytest__macos
234
261
  or ci__pull_request__pytest__ubuntu
235
262
  or ci__pull_request__pytest__windows
236
- or (ci__pull_request__pytest__sops_age_key is not None)
237
263
  or ci__pull_request__ruff
238
264
  ):
239
265
  add_ci_pull_request_yaml(
240
- certificates=ci__ca_certificates,
241
266
  gitea=ci__gitea,
242
- token=ci__token,
243
267
  modifications=modifications,
268
+ certificates=ci__certificates,
244
269
  pre_commit=ci__pull_request__pre_commit,
245
270
  pre_commit__submodules=ci__pull_request__pre_commit__submodules,
246
271
  pyright=ci__pull_request__pyright,
247
272
  pytest__macos=ci__pull_request__pytest__macos,
248
273
  pytest__ubuntu=ci__pull_request__pytest__ubuntu,
249
274
  pytest__windows=ci__pull_request__pytest__windows,
275
+ pytest__all_versions=ci__pull_request__pytest__all_versions,
250
276
  pytest__sops_age_key=ci__pull_request__pytest__sops_age_key,
251
277
  pytest__timeout=pytest__timeout,
252
278
  python_version=python_version,
253
279
  repo_name=repo_name,
254
280
  ruff=ruff,
255
281
  script=script,
282
+ token_checkout=ci__token_checkout,
283
+ token_github=ci__token_github,
256
284
  uv__native_tls=uv__native_tls,
257
285
  )
258
286
  if (
259
- ci__push__publish
260
- or (ci__push__publish__username is not None)
261
- or (ci__push__publish__password is not None)
262
- or (ci__push__publish__publish_url is not None)
287
+ ci__push__publish__github
288
+ or ci__push__publish__primary
289
+ or (ci__push__publish__primary__username is not None)
290
+ or (ci__push__publish__primary__password is not None)
291
+ or (ci__push__publish__primary__publish_url is not None)
292
+ or ci__push__publish__secondary
293
+ or (ci__push__publish__secondary__username is not None)
294
+ or (ci__push__publish__secondary__password is not None)
295
+ or (ci__push__publish__secondary__publish_url is not None)
263
296
  or ci__push__tag
264
297
  or ci__push__tag__all
265
298
  ):
266
299
  add_ci_push_yaml(
267
- certificates=ci__ca_certificates,
268
300
  gitea=ci__gitea,
269
- token=ci__token,
270
301
  modifications=modifications,
271
- publish=ci__push__publish,
272
- publish__username=ci__push__publish__username,
273
- publish__password=ci__push__publish__password,
274
- publish__publish_url=ci__push__publish__publish_url,
302
+ certificates=ci__certificates,
303
+ publish__github=ci__push__publish__github,
304
+ publish__primary=ci__push__publish__primary,
305
+ publish__primary__job_name=ci__push__publish__primary__job_name,
306
+ publish__primary__username=ci__push__publish__primary__username,
307
+ publish__primary__password=ci__push__publish__primary__password,
308
+ publish__primary__publish_url=ci__push__publish__primary__publish_url,
309
+ publish__secondary=ci__push__publish__secondary,
310
+ publish__secondary__job_name=ci__push__publish__secondary__job_name,
311
+ publish__secondary__username=ci__push__publish__secondary__username,
312
+ publish__secondary__password=ci__push__publish__secondary__password,
313
+ publish__secondary__publish_url=ci__push__publish__secondary__publish_url,
275
314
  tag=ci__push__tag,
276
315
  tag__all=ci__push__tag__all,
316
+ token_checkout=ci__token_checkout,
317
+ token_github=ci__token_github,
277
318
  uv__native_tls=uv__native_tls,
278
319
  )
279
320
  if coverage:
@@ -288,11 +329,7 @@ def conformalize_repo(
288
329
  )
289
330
  if gitignore:
290
331
  add_gitignore(modifications=modifications)
291
- if (
292
- pyproject
293
- or pyproject__project__optional_dependencies__scripts
294
- or (len(pyproject__tool__uv__indexes) >= 1)
295
- ):
332
+ if pyproject:
296
333
  add_pyproject_toml(
297
334
  modifications=modifications,
298
335
  python_version=python_version,
@@ -301,7 +338,7 @@ def conformalize_repo(
301
338
  readme=readme,
302
339
  optional_dependencies__scripts=pyproject__project__optional_dependencies__scripts,
303
340
  python_package_name=python_package_name,
304
- tool__uv__indexes=pyproject__tool__uv__indexes,
341
+ uv__indexes=uv__indexes,
305
342
  )
306
343
  if pyright:
307
344
  add_pyrightconfig_json(
@@ -338,6 +375,7 @@ def conformalize_repo(
338
375
  ", ".join(map(repr_str, sorted(modifications))),
339
376
  )
340
377
  sys.exit(1)
378
+ LOGGER.info("Finished running %r", get_func_name(conformalize_repo))
341
379
 
342
380
 
343
381
  ##
@@ -351,11 +389,11 @@ def add_bumpversion_toml(
351
389
  python_package_name: str | None = SETTINGS.python_package_name,
352
390
  ) -> None:
353
391
  with yield_bumpversion_toml(modifications=modifications) as doc:
354
- tool = get_table(doc, "tool")
355
- bumpversion = get_table(tool, "bumpversion")
392
+ tool = get_set_table(doc, "tool")
393
+ bumpversion = get_set_table(tool, "bumpversion")
356
394
  if pyproject:
357
- files = get_aot(bumpversion, "files")
358
- ensure_aot_contains(
395
+ files = get_set_aot(bumpversion, "files")
396
+ ensure_contains(
359
397
  files,
360
398
  _add_bumpversion_toml_file(PYPROJECT_TOML, 'version = "${version}"'),
361
399
  )
@@ -364,8 +402,8 @@ def add_bumpversion_toml(
364
402
  package_name=package_name, python_package_name=python_package_name
365
403
  )
366
404
  ) is not None:
367
- files = get_aot(bumpversion, "files")
368
- ensure_aot_contains(
405
+ files = get_set_aot(bumpversion, "files")
406
+ ensure_contains(
369
407
  files,
370
408
  _add_bumpversion_toml_file(
371
409
  f"src/{python_package_name_use}/__init__.py",
@@ -387,10 +425,9 @@ def _add_bumpversion_toml_file(path: PathLike, template: str, /) -> Table:
387
425
 
388
426
  def add_ci_pull_request_yaml(
389
427
  *,
390
- certificates: bool = SETTINGS.ci__ca_certificates,
391
428
  gitea: bool = SETTINGS.ci__gitea,
392
- token: str | None = SETTINGS.ci__token,
393
429
  modifications: MutableSet[Path] | None = None,
430
+ certificates: bool = SETTINGS.ci__certificates,
394
431
  pre_commit: bool = SETTINGS.ci__pull_request__pre_commit,
395
432
  pre_commit__submodules: str
396
433
  | None = SETTINGS.ci__pull_request__pre_commit__submodules,
@@ -399,76 +436,75 @@ def add_ci_pull_request_yaml(
399
436
  pytest__ubuntu: bool = SETTINGS.ci__pull_request__pytest__ubuntu,
400
437
  pytest__windows: bool = SETTINGS.ci__pull_request__pytest__windows,
401
438
  pytest__all_versions: bool = SETTINGS.ci__pull_request__pytest__all_versions,
402
- pytest__sops_age_key: str | None = SETTINGS.ci__pull_request__pytest__sops_age_key,
439
+ pytest__sops_age_key: Secret[str]
440
+ | None = SETTINGS.ci__pull_request__pytest__sops_age_key,
403
441
  pytest__timeout: int | None = SETTINGS.pytest__timeout,
404
442
  python_version: str = SETTINGS.python_version,
405
443
  repo_name: str | None = SETTINGS.repo_name,
406
444
  ruff: bool = SETTINGS.ci__pull_request__ruff,
407
445
  script: str | None = SETTINGS.script,
446
+ token_checkout: Secret[str] | None = SETTINGS.ci__token_checkout,
447
+ token_github: Secret[str] | None = SETTINGS.ci__token_github,
408
448
  uv__native_tls: bool = SETTINGS.uv__native_tls,
409
449
  ) -> None:
410
450
  path = GITEA_PULL_REQUEST_YAML if gitea else GITHUB_PULL_REQUEST_YAML
411
451
  with yield_yaml_dict(path, modifications=modifications) as dict_:
412
452
  dict_["name"] = "pull-request"
413
- on = get_dict(dict_, "on")
414
- pull_request = get_dict(on, "pull_request")
415
- branches = get_list(pull_request, "branches")
453
+ on = get_set_dict(dict_, "on")
454
+ pull_request = get_set_dict(on, "pull_request")
455
+ branches = get_set_list_strs(pull_request, "branches")
416
456
  ensure_contains(branches, "master")
417
- schedule = get_list(on, "schedule")
457
+ schedule = get_set_list_dicts(on, "schedule")
418
458
  ensure_contains(schedule, {"cron": get_cron_job(repo_name=repo_name)})
419
- jobs = get_dict(dict_, "jobs")
459
+ jobs = get_set_dict(dict_, "jobs")
420
460
  if pre_commit:
421
- pre_commit_dict = get_dict(jobs, "pre-commit")
461
+ pre_commit_dict = get_set_dict(jobs, "pre-commit")
422
462
  pre_commit_dict["runs-on"] = "ubuntu-latest"
423
- steps = get_list(pre_commit_dict, "steps")
463
+ steps = get_set_list_dicts(pre_commit_dict, "steps")
424
464
  if certificates:
425
465
  ensure_contains(steps, update_ca_certificates_dict("pre-commit"))
426
466
  ensure_contains(
427
467
  steps,
428
468
  action_run_hooks_dict(
429
- token=token,
469
+ token_checkout=token_checkout,
470
+ token_github=token_github,
430
471
  submodules=pre_commit__submodules,
431
- repos=["pre-commit/pre-commit-hooks"],
472
+ repos=["dycw/actions", "pre-commit/pre-commit-hooks"],
432
473
  gitea=gitea,
433
474
  ),
434
475
  )
435
476
  if pyright:
436
- pyright_dict = get_dict(jobs, "pyright")
477
+ pyright_dict = get_set_dict(jobs, "pyright")
437
478
  pyright_dict["runs-on"] = "ubuntu-latest"
438
- steps = get_list(pyright_dict, "steps")
479
+ steps = get_set_list_dicts(pyright_dict, "steps")
439
480
  if certificates:
440
481
  ensure_contains(steps, update_ca_certificates_dict("pyright"))
441
482
  ensure_contains(
442
483
  steps,
443
484
  action_pyright_dict(
444
- token=token,
485
+ token_checkout=token_checkout,
486
+ token_github=token_github,
445
487
  python_version=python_version,
446
488
  with_requirements=script,
447
489
  native_tls=uv__native_tls,
448
490
  ),
449
491
  )
450
- if (
451
- pytest__macos
452
- or pytest__ubuntu
453
- or pytest__windows
454
- or (pytest__sops_age_key is not None)
455
- or pytest__all_versions
456
- or pytest__timeout
457
- ):
458
- pytest_dict = get_dict(jobs, "pytest")
459
- env = get_dict(pytest_dict, "env")
492
+ if pytest__macos or pytest__ubuntu or pytest__windows:
493
+ pytest_dict = get_set_dict(jobs, "pytest")
494
+ env = get_set_dict(pytest_dict, "env")
460
495
  env["CI"] = "1"
461
496
  pytest_dict["name"] = (
462
497
  "pytest (${{matrix.os}}, ${{matrix.python-version}}, ${{matrix.resolution}})"
463
498
  )
464
499
  pytest_dict["runs-on"] = "${{matrix.os}}"
465
- steps = get_list(pytest_dict, "steps")
500
+ steps = get_set_list_dicts(pytest_dict, "steps")
466
501
  if certificates:
467
502
  ensure_contains(steps, update_ca_certificates_dict("pytest"))
468
503
  ensure_contains(
469
504
  steps,
470
505
  action_pytest_dict(
471
- token=token,
506
+ token_checkout=token_checkout,
507
+ token_github=token_github,
472
508
  python_version="${{matrix.python-version}}",
473
509
  sops_age_key=pytest__sops_age_key,
474
510
  resolution="${{matrix.resolution}}",
@@ -476,34 +512,39 @@ def add_ci_pull_request_yaml(
476
512
  with_requirements=script,
477
513
  ),
478
514
  )
479
- strategy_dict = get_dict(pytest_dict, "strategy")
515
+ strategy_dict = get_set_dict(pytest_dict, "strategy")
480
516
  strategy_dict["fail-fast"] = False
481
- matrix = get_dict(strategy_dict, "matrix")
482
- os = get_list(matrix, "os")
517
+ matrix = get_set_dict(strategy_dict, "matrix")
518
+ os = get_set_list_strs(matrix, "os")
483
519
  if pytest__macos:
484
520
  ensure_contains(os, "macos-latest")
485
521
  if pytest__ubuntu:
486
522
  ensure_contains(os, "ubuntu-latest")
487
523
  if pytest__windows:
488
524
  ensure_contains(os, "windows-latest")
489
- python_version_dict = get_list(matrix, "python-version")
525
+ python_version_dict = get_set_list_strs(matrix, "python-version")
490
526
  if pytest__all_versions:
491
527
  ensure_contains(
492
528
  python_version_dict, *yield_python_versions(python_version)
493
529
  )
494
530
  else:
495
531
  ensure_contains(python_version_dict, python_version)
496
- resolution = get_list(matrix, "resolution")
532
+ resolution = get_set_list_strs(matrix, "resolution")
497
533
  ensure_contains(resolution, "highest", "lowest-direct")
498
534
  if pytest__timeout is not None:
499
535
  pytest_dict["timeout-minutes"] = max(round(pytest__timeout / 60), 1)
500
536
  if ruff:
501
- ruff_dict = get_dict(jobs, "ruff")
537
+ ruff_dict = get_set_dict(jobs, "ruff")
502
538
  ruff_dict["runs-on"] = "ubuntu-latest"
503
- steps = get_list(ruff_dict, "steps")
539
+ steps = get_set_list_dicts(ruff_dict, "steps")
504
540
  if certificates:
505
541
  ensure_contains(steps, update_ca_certificates_dict("steps"))
506
- ensure_contains(steps, action_ruff_dict(token=token))
542
+ ensure_contains(
543
+ steps,
544
+ action_ruff_dict(
545
+ token_checkout=token_checkout, token_github=token_github
546
+ ),
547
+ )
507
548
 
508
549
 
509
550
  ##
@@ -511,50 +552,76 @@ def add_ci_pull_request_yaml(
511
552
 
512
553
  def add_ci_push_yaml(
513
554
  *,
514
- certificates: bool = SETTINGS.ci__ca_certificates,
515
555
  gitea: bool = SETTINGS.ci__gitea,
516
- token: str | None = SETTINGS.ci__token,
517
556
  modifications: MutableSet[Path] | None = None,
518
- publish: bool = SETTINGS.ci__push__publish,
519
- publish__username: str | None = SETTINGS.ci__push__publish__username,
520
- publish__password: Secret[str] | None = SETTINGS.ci__push__publish__password,
521
- publish__publish_url: Secret[str] | None = SETTINGS.ci__push__publish__publish_url,
557
+ certificates: bool = SETTINGS.ci__certificates,
558
+ publish__github: bool = SETTINGS.ci__push__publish__github,
559
+ publish__primary: bool = SETTINGS.ci__push__publish__primary,
560
+ publish__primary__job_name: str = SETTINGS.ci__push__publish__primary__job_name,
561
+ publish__primary__username: str
562
+ | None = SETTINGS.ci__push__publish__primary__username,
563
+ publish__primary__password: Secret[str]
564
+ | None = SETTINGS.ci__push__publish__primary__password,
565
+ publish__primary__publish_url: str
566
+ | None = SETTINGS.ci__push__publish__primary__publish_url,
567
+ publish__secondary: bool = SETTINGS.ci__push__publish__secondary,
568
+ publish__secondary__job_name: str = SETTINGS.ci__push__publish__secondary__job_name,
569
+ publish__secondary__username: str
570
+ | None = SETTINGS.ci__push__publish__secondary__username,
571
+ publish__secondary__password: Secret[str]
572
+ | None = SETTINGS.ci__push__publish__secondary__password,
573
+ publish__secondary__publish_url: str
574
+ | None = SETTINGS.ci__push__publish__secondary__publish_url,
522
575
  tag: bool = SETTINGS.ci__push__tag,
523
576
  tag__all: bool = SETTINGS.ci__push__tag__all,
577
+ token_checkout: Secret[str] | None = SETTINGS.ci__token_checkout,
578
+ token_github: Secret[str] | None = SETTINGS.ci__token_github,
524
579
  uv__native_tls: bool = SETTINGS.uv__native_tls,
525
580
  ) -> None:
526
581
  path = GITEA_PUSH_YAML if gitea else GITHUB_PUSH_YAML
527
582
  with yield_yaml_dict(path, modifications=modifications) as dict_:
528
583
  dict_["name"] = "push"
529
- on = get_dict(dict_, "on")
530
- push = get_dict(on, "push")
531
- branches = get_list(push, "branches")
584
+ on = get_set_dict(dict_, "on")
585
+ push = get_set_dict(on, "push")
586
+ branches = get_set_list_strs(push, "branches")
532
587
  ensure_contains(branches, "master")
533
- jobs = get_dict(dict_, "jobs")
534
- if publish:
535
- publish_dict = get_dict(jobs, "publish")
536
- environment = get_dict(publish_dict, "environment")
537
- environment["name"] = "pypi"
538
- permissions = get_dict(publish_dict, "permissions")
539
- permissions["id-token"] = "write"
540
- publish_dict["runs-on"] = "ubuntu-latest"
541
- steps = get_list(publish_dict, "steps")
542
- if certificates:
543
- ensure_contains(steps, update_ca_certificates_dict("publish"))
544
- ensure_contains(
545
- steps,
546
- action_publish_package_dict(
547
- token=token,
548
- username=publish__username,
549
- password=publish__password,
550
- publish_url=publish__publish_url,
551
- native_tls=uv__native_tls,
552
- ),
588
+ jobs = get_set_dict(dict_, "jobs")
589
+ if publish__github:
590
+ _add_ci_push_yaml_publish_dict(
591
+ jobs,
592
+ "github",
593
+ github=True,
594
+ token_checkout=token_checkout,
595
+ token_github=token_github,
596
+ )
597
+ if publish__primary:
598
+ _add_ci_push_yaml_publish_dict(
599
+ jobs,
600
+ publish__primary__job_name,
601
+ certificates=certificates,
602
+ token_checkout=token_checkout,
603
+ token_github=token_github,
604
+ username=publish__primary__username,
605
+ password=publish__primary__password,
606
+ publish_url=publish__primary__publish_url,
607
+ uv__native_tls=uv__native_tls,
608
+ )
609
+ if publish__secondary:
610
+ _add_ci_push_yaml_publish_dict(
611
+ jobs,
612
+ publish__secondary__job_name,
613
+ certificates=certificates,
614
+ token_checkout=token_checkout,
615
+ token_github=token_github,
616
+ username=publish__secondary__username,
617
+ password=publish__secondary__password,
618
+ publish_url=publish__secondary__publish_url,
619
+ uv__native_tls=uv__native_tls,
553
620
  )
554
621
  if tag:
555
- tag_dict = get_dict(jobs, "tag")
622
+ tag_dict = get_set_dict(jobs, "tag")
556
623
  tag_dict["runs-on"] = "ubuntu-latest"
557
- steps = get_list(tag_dict, "steps")
624
+ steps = get_set_list_dicts(tag_dict, "steps")
558
625
  if certificates:
559
626
  ensure_contains(steps, update_ca_certificates_dict("tag"))
560
627
  ensure_contains(
@@ -565,20 +632,58 @@ def add_ci_push_yaml(
565
632
  )
566
633
 
567
634
 
635
+ def _add_ci_push_yaml_publish_dict(
636
+ jobs: StrDict,
637
+ name: str,
638
+ /,
639
+ *,
640
+ github: bool = False,
641
+ certificates: bool = SETTINGS.ci__certificates,
642
+ token_checkout: Secret[str] | None = SETTINGS.ci__token_checkout,
643
+ token_github: Secret[str] | None = SETTINGS.ci__token_github,
644
+ username: str | None = None,
645
+ password: Secret[str] | None = None,
646
+ publish_url: str | None = None,
647
+ uv__native_tls: bool = SETTINGS.uv__native_tls,
648
+ ) -> None:
649
+ publish_name = f"publish-{name}"
650
+ publish_dict = get_set_dict(jobs, publish_name)
651
+ if github:
652
+ environment = get_set_dict(publish_dict, "environment")
653
+ environment["name"] = "pypi"
654
+ permissions = get_set_dict(publish_dict, "permissions")
655
+ permissions["id-token"] = "write"
656
+ publish_dict["runs-on"] = "ubuntu-latest"
657
+ steps = get_set_list_dicts(publish_dict, "steps")
658
+ if certificates:
659
+ ensure_contains(steps, update_ca_certificates_dict(publish_name))
660
+ ensure_contains(
661
+ steps,
662
+ action_publish_package_dict(
663
+ token_checkout=token_checkout,
664
+ token_github=token_github,
665
+ username=username,
666
+ password=password,
667
+ publish_url=publish_url,
668
+ native_tls=uv__native_tls,
669
+ ),
670
+ )
671
+
672
+
568
673
  ##
569
674
 
570
675
 
571
676
  def add_coveragerc_toml(*, modifications: MutableSet[Path] | None = None) -> None:
572
677
  with yield_toml_doc(COVERAGERC_TOML, modifications=modifications) as doc:
573
- html = get_table(doc, "html")
678
+ html = get_set_table(doc, "html")
574
679
  html["directory"] = ".coverage/html"
575
- report = get_table(doc, "report")
576
- exclude_also = get_array(report, "exclude_also")
680
+ report = get_set_table(doc, "report")
681
+ exclude_also = get_set_array(report, "exclude_also")
577
682
  ensure_contains(exclude_also, "@overload", "if TYPE_CHECKING:")
578
683
  report["fail_under"] = 100.0
579
684
  report["skip_covered"] = True
580
685
  report["skip_empty"] = True
581
- run = get_table(doc, "run")
686
+ run = get_set_table(doc, "run")
582
687
  run["branch"] = True
583
688
  run["data_file"] = ".coverage/data"
584
689
  run["parallel"] = True
@@ -615,7 +720,7 @@ def add_envrc(
615
720
  native_tls=uv__native_tls, python_version=python_version, script=script
616
721
  )
617
722
  if search(escape(uv_text), context.output, flags=MULTILINE) is None:
618
- context.output += f"\n\n{echo}"
723
+ context.output += f"\n\n{uv_text}"
619
724
 
620
725
 
621
726
  def _add_envrc_uv_text(
@@ -636,14 +741,15 @@ def _add_envrc_uv_text(
636
741
  strip_and_dedent(f"""
637
742
  export UV_PRERELEASE='disallow'
638
743
  export UV_PYTHON='{python_version}'
744
+ export UV_VENV_CLEAR=1
639
745
  if ! command -v uv >/dev/null 2>&1; then
640
- echo_date "ERROR: 'uv' not found" && exit 1
746
+ \techo_date "ERROR: 'uv' not found" && exit 1
641
747
  fi
642
748
  activate='.venv/bin/activate'
643
749
  if [ -f $activate ]; then
644
- . $activate
750
+ \t. $activate
645
751
  else
646
- uv venv
752
+ \tuv venv
647
753
  fi
648
754
  """)
649
755
  )
@@ -681,6 +787,8 @@ def add_pre_commit_config_yaml(
681
787
  taplo: bool = SETTINGS.pre_commit__taplo,
682
788
  uv: bool = SETTINGS.pre_commit__uv,
683
789
  script: str | None = SETTINGS.script,
790
+ uv__indexes: list[tuple[str, str]] = SETTINGS.uv__indexes,
791
+ uv__native_tls: bool = SETTINGS.uv__native_tls,
684
792
  ) -> None:
685
793
  with yield_yaml_dict(PRE_COMMIT_CONFIG_YAML, modifications=modifications) as dict_:
686
794
  _add_pre_commit_config_repo(dict_, ACTIONS_URL, CONFORMALIZE_REPO_SUB_CMD)
@@ -728,7 +836,17 @@ def add_pre_commit_config_yaml(
728
836
  )
729
837
  _add_pre_commit_config_repo(dict_, ACTIONS_URL, TOUCH_EMPTY_PY_SUB_CMD)
730
838
  _add_pre_commit_config_repo(dict_, ACTIONS_URL, TOUCH_PY_TYPED_SUB_CMD)
731
- _add_pre_commit_config_repo(dict_, ACTIONS_URL, UPDATE_REQUIREMENTS_SUB_CMD)
839
+ args: list[str] = []
840
+ if len(uv__indexes) >= 1:
841
+ args.extend(["--index", ",".join(v for _, v in uv__indexes)])
842
+ if uv__native_tls:
843
+ args.append("--native-tls")
844
+ _add_pre_commit_config_repo(
845
+ dict_,
846
+ ACTIONS_URL,
847
+ UPDATE_REQUIREMENTS_SUB_CMD,
848
+ args=("add", args) if len(args) >= 1 else None,
849
+ )
732
850
  if ruff:
733
851
  _add_pre_commit_config_repo(
734
852
  dict_, RUFF_URL, "ruff-check", args=("add", ["--fix"])
@@ -755,16 +873,21 @@ def add_pre_commit_config_yaml(
755
873
  ),
756
874
  )
757
875
  if uv:
876
+ args: list[str] = [
877
+ "--upgrade",
878
+ "--resolution",
879
+ "highest",
880
+ "--prerelease",
881
+ "disallow",
882
+ ]
883
+ if script is not None:
884
+ args.extend(["--script", script])
758
885
  _add_pre_commit_config_repo(
759
886
  dict_,
760
887
  UV_URL,
761
888
  "uv-lock",
762
889
  files=None if script is None else rf"^{escape(script)}$",
763
- args=(
764
- "add",
765
- ["--upgrade", "--resolution", "highest", "--prerelease", "disallow"]
766
- + ([] if script is None else [f"--script={script}"]),
767
- ),
890
+ args=("add", args),
768
891
  )
769
892
 
770
893
 
@@ -781,11 +904,11 @@ def _add_pre_commit_config_repo(
781
904
  types_or: list[str] | None = None,
782
905
  args: tuple[Literal["add", "exact"], list[str]] | None = None,
783
906
  ) -> None:
784
- repos_list = get_list(pre_commit_dict, "repos")
907
+ repos_list = get_set_list_dicts(pre_commit_dict, "repos")
785
908
  repo_dict = ensure_contains_partial_dict(
786
909
  repos_list, {"repo": url}, extra={} if url == "local" else {"rev": "master"}
787
910
  )
788
- hooks_list = get_list(repo_dict, "hooks")
911
+ hooks_list = get_set_list_dicts(repo_dict, "hooks")
789
912
  hook_dict = ensure_contains_partial_dict(hooks_list, {"id": id_})
790
913
  if name is not None:
791
914
  hook_dict["name"] = name
@@ -800,7 +923,7 @@ def _add_pre_commit_config_repo(
800
923
  if args is not None:
801
924
  match args:
802
925
  case "add", list() as args_i:
803
- hook_args = get_list(hook_dict, "args")
926
+ hook_args = get_set_list_strs(hook_dict, "args")
804
927
  ensure_contains(hook_args, *args_i)
805
928
  case "exact", list() as args_i:
806
929
  hook_dict["args"] = args_i
@@ -820,13 +943,13 @@ def add_pyproject_toml(
820
943
  readme: bool = SETTINGS.readme,
821
944
  optional_dependencies__scripts: bool = SETTINGS.pyproject__project__optional_dependencies__scripts,
822
945
  python_package_name: str | None = SETTINGS.python_package_name,
823
- tool__uv__indexes: list[tuple[str, str]] = SETTINGS.pyproject__tool__uv__indexes,
946
+ uv__indexes: list[tuple[str, str]] = SETTINGS.uv__indexes,
824
947
  ) -> None:
825
- with yield_toml_doc(PYPROJECT_TOML, modifications=modifications) as doc:
826
- build_system = get_table(doc, "build-system")
948
+ with yield_pyproject_toml(modifications=modifications) as doc:
949
+ build_system = get_set_table(doc, "build-system")
827
950
  build_system["build-backend"] = "uv_build"
828
951
  build_system["requires"] = ["uv_build"]
829
- project = get_table(doc, "project")
952
+ project = get_set_table(doc, "project")
830
953
  project["requires-python"] = f">= {python_version}"
831
954
  if description is not None:
832
955
  project["description"] = description
@@ -835,33 +958,31 @@ def add_pyproject_toml(
835
958
  if readme:
836
959
  project["readme"] = "README.md"
837
960
  project.setdefault("version", "0.1.0")
838
- dependency_groups = get_table(doc, "dependency-groups")
839
- dev = get_array(dependency_groups, "dev")
961
+ dependency_groups = get_set_table(doc, "dependency-groups")
962
+ dev = get_set_array(dependency_groups, "dev")
840
963
  _ = ensure_contains_partial_str(dev, "dycw-utilities[test]")
841
964
  _ = ensure_contains_partial_str(dev, "pyright")
842
965
  _ = ensure_contains_partial_str(dev, "rich")
843
966
  if optional_dependencies__scripts:
844
- optional_dependencies = get_table(project, "optional-dependencies")
845
- scripts = get_array(optional_dependencies, "scripts")
967
+ optional_dependencies = get_set_table(project, "optional-dependencies")
968
+ scripts = get_set_array(optional_dependencies, "scripts")
846
969
  _ = ensure_contains_partial_str(scripts, "click")
847
970
  if python_package_name is not None:
848
- tool = get_table(doc, "tool")
849
- uv = get_table(tool, "uv")
850
- build_backend = get_table(uv, "build-backend")
971
+ uv = get_tool_uv(doc)
972
+ build_backend = get_set_table(uv, "build-backend")
851
973
  build_backend["module-name"] = get_python_package_name(
852
974
  package_name=package_name, python_package_name=python_package_name
853
975
  )
854
976
  build_backend["module-root"] = "src"
855
- if len(tool__uv__indexes) >= 1:
856
- tool = get_table(doc, "tool")
857
- uv = get_table(tool, "uv")
858
- indexes = get_aot(uv, "index")
859
- for name, url in tool__uv__indexes:
977
+ if len(uv__indexes) >= 1:
978
+ uv = get_tool_uv(doc)
979
+ indexes = get_set_aot(uv, "index")
980
+ for name, url in uv__indexes:
860
981
  index = table()
861
982
  index["explicit"] = True
862
983
  index["name"] = name
863
984
  index["url"] = url
864
- ensure_aot_contains(indexes, index)
985
+ ensure_contains(indexes, index)
865
986
 
866
987
 
867
988
  ##
@@ -876,7 +997,7 @@ def add_pyrightconfig_json(
876
997
  with yield_json_dict(PYRIGHTCONFIG_JSON, modifications=modifications) as dict_:
877
998
  dict_["deprecateTypingAliases"] = True
878
999
  dict_["enableReachabilityAnalysis"] = False
879
- include = get_list(dict_, "include")
1000
+ include = get_set_list_strs(dict_, "include")
880
1001
  ensure_contains(include, "src" if script is None else script)
881
1002
  dict_["pythonVersion"] = python_version
882
1003
  dict_["reportCallInDefaultInitializer"] = True
@@ -917,8 +1038,8 @@ def add_pytest_toml(
917
1038
  script: str | None = SETTINGS.script,
918
1039
  ) -> None:
919
1040
  with yield_toml_doc(PYTEST_TOML, modifications=modifications) as doc:
920
- pytest = get_table(doc, "pytest")
921
- addopts = get_array(pytest, "addopts")
1041
+ pytest = get_set_table(doc, "pytest")
1042
+ addopts = get_set_array(pytest, "addopts")
922
1043
  ensure_contains(
923
1044
  addopts,
924
1045
  "-ra",
@@ -943,18 +1064,18 @@ def add_pytest_toml(
943
1064
  )
944
1065
  pytest["collect_imported_tests"] = False
945
1066
  pytest["empty_parameter_set_mark"] = "fail_at_collect"
946
- filterwarnings = get_array(pytest, "filterwarnings")
1067
+ filterwarnings = get_set_array(pytest, "filterwarnings")
947
1068
  ensure_contains(filterwarnings, "error")
948
1069
  pytest["minversion"] = "9.0"
949
1070
  pytest["strict"] = True
950
- testpaths = get_array(pytest, "testpaths")
1071
+ testpaths = get_set_array(pytest, "testpaths")
951
1072
  ensure_contains(testpaths, "src/tests" if script is None else "tests")
952
1073
  pytest["xfail_strict"] = True
953
1074
  if asyncio:
954
1075
  pytest["asyncio_default_fixture_loop_scope"] = "function"
955
1076
  pytest["asyncio_mode"] = "auto"
956
1077
  if ignore_warnings:
957
- filterwarnings = get_array(pytest, "filterwarnings")
1078
+ filterwarnings = get_set_array(pytest, "filterwarnings")
958
1079
  ensure_contains(
959
1080
  filterwarnings,
960
1081
  "ignore::DeprecationWarning",
@@ -996,14 +1117,14 @@ def add_ruff_toml(
996
1117
  with yield_toml_doc(RUFF_TOML, modifications=modifications) as doc:
997
1118
  doc["target-version"] = f"py{python_version.replace('.', '')}"
998
1119
  doc["unsafe-fixes"] = True
999
- fmt = get_table(doc, "format")
1120
+ fmt = get_set_table(doc, "format")
1000
1121
  fmt["preview"] = True
1001
1122
  fmt["skip-magic-trailing-comma"] = True
1002
- lint = get_table(doc, "lint")
1123
+ lint = get_set_table(doc, "lint")
1003
1124
  lint["explicit-preview-rules"] = True
1004
- fixable = get_array(lint, "fixable")
1125
+ fixable = get_set_array(lint, "fixable")
1005
1126
  ensure_contains(fixable, "ALL")
1006
- ignore = get_array(lint, "ignore")
1127
+ ignore = get_set_array(lint, "ignore")
1007
1128
  ensure_contains(
1008
1129
  ignore,
1009
1130
  "ANN401", # any-type
@@ -1044,27 +1165,27 @@ def add_ruff_toml(
1044
1165
  "ISC002", # multi-line-implicit-string-concatenation
1045
1166
  )
1046
1167
  lint["preview"] = True
1047
- select = get_array(lint, "select")
1168
+ select = get_set_array(lint, "select")
1048
1169
  selected_rules = [
1049
1170
  "RUF022", # unsorted-dunder-all
1050
1171
  "RUF029", # unused-async
1051
1172
  ]
1052
1173
  ensure_contains(select, "ALL", *selected_rules)
1053
- extend_per_file_ignores = get_table(lint, "extend-per-file-ignores")
1054
- test_py = get_array(extend_per_file_ignores, "test_*.py")
1174
+ extend_per_file_ignores = get_set_table(lint, "extend-per-file-ignores")
1175
+ test_py = get_set_array(extend_per_file_ignores, "test_*.py")
1055
1176
  test_py_rules = [
1056
1177
  "S101", # assert
1057
1178
  "SLF001", # private-member-access
1058
1179
  ]
1059
1180
  ensure_contains(test_py, *test_py_rules)
1060
1181
  ensure_not_contains(ignore, *selected_rules, *test_py_rules)
1061
- bugbear = get_table(lint, "flake8-bugbear")
1062
- extend_immutable_calls = get_array(bugbear, "extend-immutable-calls")
1182
+ bugbear = get_set_table(lint, "flake8-bugbear")
1183
+ extend_immutable_calls = get_set_array(bugbear, "extend-immutable-calls")
1063
1184
  ensure_contains(extend_immutable_calls, "typing.cast")
1064
- tidy_imports = get_table(lint, "flake8-tidy-imports")
1185
+ tidy_imports = get_set_table(lint, "flake8-tidy-imports")
1065
1186
  tidy_imports["ban-relative-imports"] = "all"
1066
- isort = get_table(lint, "isort")
1067
- req_imps = get_array(isort, "required-imports")
1187
+ isort = get_set_table(lint, "isort")
1188
+ req_imps = get_set_array(isort, "required-imports")
1068
1189
  ensure_contains(req_imps, "from __future__ import annotations")
1069
1190
  isort["split-on-trailing-comma"] = False
1070
1191
 
@@ -1113,13 +1234,21 @@ def get_python_package_name(
1113
1234
  ##
1114
1235
 
1115
1236
 
1237
+ def get_tool_uv(doc: TOMLDocument, /) -> Table:
1238
+ tool = get_set_table(doc, "tool")
1239
+ return get_set_table(tool, "uv")
1240
+
1241
+
1242
+ ##
1243
+
1244
+
1116
1245
  def get_version_from_bumpversion_toml(
1117
1246
  *, obj: TOMLDocument | str | None = None
1118
1247
  ) -> Version:
1119
1248
  match obj:
1120
1249
  case TOMLDocument() as doc:
1121
- tool = get_table(doc, "tool")
1122
- bumpversion = get_table(tool, "bumpversion")
1250
+ tool = get_set_table(doc, "tool")
1251
+ bumpversion = get_set_table(tool, "bumpversion")
1123
1252
  return parse_version(str(bumpversion["current_version"]))
1124
1253
  case str() as text:
1125
1254
  return get_version_from_bumpversion_toml(obj=tomlkit.parse(text))
@@ -1179,7 +1308,7 @@ def _run_pre_commit_update(*, modifications: MutableSet[Path] | None = None) ->
1179
1308
 
1180
1309
 
1181
1310
  run_pre_commit_update = throttle(
1182
- delta=THROTTLE_DELTA, path=path_throttle_cache(_run_pre_commit_update)
1311
+ duration=THROTTLE_DURATION, path=path_throttle_cache(_run_pre_commit_update)
1183
1312
  )(_run_pre_commit_update)
1184
1313
 
1185
1314
 
@@ -1245,7 +1374,7 @@ def update_action_file_extensions(
1245
1374
 
1246
1375
  def update_action_versions(*, modifications: MutableSet[Path] | None = None) -> None:
1247
1376
  try:
1248
- paths = list(Path(".github").rglob("**/*.yaml"))
1377
+ paths = list(GITHUB.rglob("**/*.yaml"))
1249
1378
  except FileNotFoundError:
1250
1379
  return
1251
1380
  versions = {
@@ -1274,8 +1403,8 @@ def yield_bumpversion_toml(
1274
1403
  *, modifications: MutableSet[Path] | None = None
1275
1404
  ) -> Iterator[TOMLDocument]:
1276
1405
  with yield_toml_doc(BUMPVERSION_TOML, modifications=modifications) as doc:
1277
- tool = get_table(doc, "tool")
1278
- bumpversion = get_table(tool, "bumpversion")
1406
+ tool = get_set_table(doc, "tool")
1407
+ bumpversion = get_set_table(tool, "bumpversion")
1279
1408
  bumpversion["allow_dirty"] = True
1280
1409
  bumpversion.setdefault("current_version", str(Version(0, 1, 0)))
1281
1410
  yield doc
@@ -1323,6 +1452,7 @@ __all__ = [
1323
1452
  "check_versions",
1324
1453
  "get_cron_job",
1325
1454
  "get_python_package_name",
1455
+ "get_tool_uv",
1326
1456
  "get_version_from_bumpversion_toml",
1327
1457
  "get_version_from_git_show",
1328
1458
  "get_version_from_git_tag",