dycw-actions 0.6.4__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 (64) hide show
  1. actions/__init__.py +1 -1
  2. actions/action_dicts/lib.py +8 -8
  3. actions/clean_dir/cli.py +0 -12
  4. actions/clean_dir/constants.py +7 -0
  5. actions/cli.py +81 -30
  6. actions/pre_commit/click.py +15 -0
  7. actions/{conformalize_repo → pre_commit/conformalize_repo}/cli.py +2 -14
  8. actions/{conformalize_repo → pre_commit/conformalize_repo}/constants.py +8 -2
  9. actions/{conformalize_repo → pre_commit/conformalize_repo}/lib.py +79 -308
  10. actions/{conformalize_repo → pre_commit/conformalize_repo}/settings.py +1 -1
  11. actions/pre_commit/constants.py +8 -0
  12. actions/pre_commit/format_requirements/cli.py +24 -0
  13. actions/pre_commit/format_requirements/constants.py +7 -0
  14. actions/pre_commit/format_requirements/lib.py +52 -0
  15. actions/pre_commit/replace_sequence_strs/__init__.py +1 -0
  16. actions/pre_commit/replace_sequence_strs/cli.py +24 -0
  17. actions/pre_commit/replace_sequence_strs/constants.py +7 -0
  18. actions/{replace_sequence_strs → pre_commit/replace_sequence_strs}/lib.py +16 -22
  19. actions/pre_commit/touch_empty_py/__init__.py +1 -0
  20. actions/pre_commit/touch_empty_py/cli.py +24 -0
  21. actions/pre_commit/touch_empty_py/constants.py +7 -0
  22. actions/pre_commit/touch_empty_py/lib.py +54 -0
  23. actions/pre_commit/touch_py_typed/__init__.py +1 -0
  24. actions/pre_commit/touch_py_typed/cli.py +24 -0
  25. actions/pre_commit/touch_py_typed/constants.py +7 -0
  26. actions/pre_commit/touch_py_typed/lib.py +64 -0
  27. actions/pre_commit/update_requirements/__init__.py +1 -0
  28. actions/pre_commit/update_requirements/classes.py +117 -0
  29. actions/pre_commit/update_requirements/cli.py +24 -0
  30. actions/pre_commit/update_requirements/constants.py +7 -0
  31. actions/pre_commit/update_requirements/lib.py +128 -0
  32. actions/pre_commit/utilities.py +386 -0
  33. actions/publish_package/cli.py +7 -19
  34. actions/publish_package/constants.py +7 -0
  35. actions/publish_package/lib.py +3 -3
  36. actions/py.typed +0 -0
  37. actions/random_sleep/cli.py +6 -15
  38. actions/random_sleep/constants.py +7 -0
  39. actions/run_hooks/cli.py +3 -15
  40. actions/run_hooks/constants.py +7 -0
  41. actions/run_hooks/lib.py +2 -2
  42. actions/setup_cronjob/cli.py +0 -12
  43. actions/setup_cronjob/constants.py +5 -1
  44. actions/tag_commit/cli.py +7 -19
  45. actions/tag_commit/constants.py +7 -0
  46. actions/tag_commit/lib.py +8 -8
  47. actions/types.py +4 -1
  48. actions/utilities.py +68 -14
  49. {dycw_actions-0.6.4.dist-info → dycw_actions-0.7.1.dist-info}/METADATA +3 -2
  50. dycw_actions-0.7.1.dist-info/RECORD +77 -0
  51. actions/format_requirements/cli.py +0 -37
  52. actions/format_requirements/lib.py +0 -121
  53. actions/publish_package/doc.py +0 -6
  54. actions/random_sleep/doc.py +0 -6
  55. actions/replace_sequence_strs/cli.py +0 -37
  56. actions/run_hooks/doc.py +0 -6
  57. actions/tag_commit/doc.py +0 -6
  58. dycw_actions-0.6.4.dist-info/RECORD +0 -56
  59. /actions/{conformalize_repo → pre_commit}/__init__.py +0 -0
  60. /actions/{format_requirements → pre_commit/conformalize_repo}/__init__.py +0 -0
  61. /actions/{conformalize_repo → pre_commit/conformalize_repo}/configs/gitignore +0 -0
  62. /actions/{replace_sequence_strs → pre_commit/format_requirements}/__init__.py +0 -0
  63. {dycw_actions-0.6.4.dist-info → dycw_actions-0.7.1.dist-info}/WHEEL +0 -0
  64. {dycw_actions-0.6.4.dist-info → dycw_actions-0.7.1.dist-info}/entry_points.txt +0 -0
@@ -1,31 +1,23 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
4
3
  import sys
5
4
  from contextlib import contextmanager, suppress
6
- from io import StringIO
7
5
  from itertools import product
8
6
  from pathlib import Path
9
- from re import MULTILINE, escape, sub
7
+ from re import MULTILINE, escape, search, sub
10
8
  from shlex import join
11
9
  from string import Template
12
10
  from subprocess import CalledProcessError
13
- from typing import TYPE_CHECKING, Any, Literal, assert_never
11
+ from typing import TYPE_CHECKING, Literal, assert_never
14
12
 
15
13
  import tomlkit
16
- from rich.pretty import pretty_repr
17
14
  from ruamel.yaml.scalarstring import LiteralScalarString
18
- from tomlkit import TOMLDocument, aot, array, document, table
15
+ from tomlkit import TOMLDocument, table
19
16
  from tomlkit.exceptions import NonExistentKey
20
- from tomlkit.items import AoT, Array, Table
21
- from utilities.atomicwrites import writer
22
- from utilities.functions import ensure_class
23
17
  from utilities.inflect import counted_noun
24
- from utilities.iterables import OneEmptyError, OneNonUniqueError, one
25
18
  from utilities.pathlib import get_repo_root
26
19
  from utilities.re import extract_groups
27
- from utilities.subprocess import append_text, ripgrep, run
28
- from utilities.tempfile import TemporaryFile
20
+ from utilities.subprocess import ripgrep
29
21
  from utilities.text import repr_str, strip_and_dedent
30
22
  from utilities.version import ParseVersionError, Version, parse_version
31
23
  from utilities.whenever import HOUR, get_now
@@ -41,9 +33,12 @@ from actions.action_dicts.lib import (
41
33
  run_action_ruff_dict,
42
34
  run_action_tag_dict,
43
35
  )
44
- from actions.conformalize_repo.constants import (
36
+ from actions.constants import YAML_INSTANCE
37
+ from actions.logging import LOGGER
38
+ from actions.pre_commit.conformalize_repo.constants import (
45
39
  ACTIONS_URL,
46
40
  BUMPVERSION_TOML,
41
+ CONFORMALIZE_REPO_SUB_CMD,
47
42
  COVERAGERC_TOML,
48
43
  DOCKERFMT_URL,
49
44
  ENVRC,
@@ -65,16 +60,38 @@ from actions.conformalize_repo.constants import (
65
60
  TAPLO_URL,
66
61
  UV_URL,
67
62
  )
68
- from actions.conformalize_repo.settings import SETTINGS
69
- from actions.constants import YAML_INSTANCE
70
- from actions.logging import LOGGER
63
+ from actions.pre_commit.conformalize_repo.settings import SETTINGS
64
+ from actions.pre_commit.format_requirements.constants import FORMAT_REQUIREMENTS_SUB_CMD
65
+ from actions.pre_commit.replace_sequence_strs.constants import (
66
+ REPLACE_SEQUENCE_STRS_SUB_CMD,
67
+ )
68
+ from actions.pre_commit.touch_empty_py.constants import TOUCH_EMPTY_PY_SUB_CMD
69
+ from actions.pre_commit.touch_py_typed.constants import TOUCH_PY_TYPED_SUB_CMD
70
+ from actions.pre_commit.utilities import (
71
+ ensure_aot_contains,
72
+ ensure_contains,
73
+ ensure_contains_partial_dict,
74
+ ensure_contains_partial_str,
75
+ ensure_not_contains,
76
+ get_aot,
77
+ get_array,
78
+ get_dict,
79
+ get_list,
80
+ get_table,
81
+ yield_json_dict,
82
+ yield_text_file,
83
+ yield_toml_doc,
84
+ yield_yaml_dict,
85
+ )
86
+ from actions.utilities import logged_run, write_text
71
87
 
72
88
  if TYPE_CHECKING:
73
- from collections.abc import Callable, Iterable, Iterator, MutableSet
89
+ from collections.abc import Iterator, MutableSet
74
90
 
91
+ from tomlkit.items import Table
75
92
  from utilities.types import PathLike
76
93
 
77
- from actions.types import HasAppend, HasSetDefault, StrDict
94
+ from actions.types import StrDict
78
95
 
79
96
 
80
97
  def conformalize_repo(
@@ -411,31 +428,27 @@ def add_envrc(
411
428
  python_version: str = SETTINGS.python_version,
412
429
  script: str | None = SETTINGS.script,
413
430
  ) -> None:
414
- with yield_text_file(ENVRC, modifications=modifications) as temp:
431
+ with yield_text_file(ENVRC, modifications=modifications) as context:
415
432
  shebang = strip_and_dedent("""
416
433
  #!/usr/bin/env sh
417
434
  # shellcheck source=/dev/null
418
435
  """)
419
- append_text(temp, shebang, skip_if_present=True, flags=MULTILINE, blank_lines=2)
436
+ if search(escape(shebang), context.output, flags=MULTILINE) is None:
437
+ context.output += f"\n\n{shebang}"
420
438
 
421
439
  echo = strip_and_dedent("""
422
440
  # echo
423
441
  echo_date() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2; }
424
442
  """)
425
- append_text(temp, echo, skip_if_present=True, flags=MULTILINE, blank_lines=2)
443
+ if search(escape(echo), context.output, flags=MULTILINE) is None:
444
+ context.output += f"\n\n{echo}"
426
445
 
427
446
  if uv:
428
- append_text(
429
- temp,
430
- _add_envrc_uv_text(
431
- native_tls=uv__native_tls,
432
- python_version=python_version,
433
- script=script,
434
- ),
435
- skip_if_present=True,
436
- flags=MULTILINE,
437
- blank_lines=2,
447
+ uv_text = _add_envrc_uv_text(
448
+ native_tls=uv__native_tls, python_version=python_version, script=script
438
449
  )
450
+ if search(escape(uv_text), context.output, flags=MULTILINE) is None:
451
+ context.output += f"\n\n{echo}"
439
452
 
440
453
 
441
454
  def _add_envrc_uv_text(
@@ -615,9 +628,10 @@ def add_github_push_yaml(
615
628
 
616
629
 
617
630
  def add_gitignore(*, modifications: MutableSet[Path] | None = None) -> None:
618
- with yield_text_file(GITIGNORE, modifications=modifications) as temp:
631
+ with yield_text_file(GITIGNORE, modifications=modifications) as context:
619
632
  text = (PATH_CONFIGS / "gitignore").read_text()
620
- append_text(temp, text, skip_if_present=True, flags=MULTILINE)
633
+ if search(escape(text), context.output, flags=MULTILINE) is None:
634
+ context.output += f"\n\n{text}"
621
635
 
622
636
 
623
637
  ##
@@ -636,7 +650,7 @@ def add_pre_commit_config_yaml(
636
650
  script: str | None = SETTINGS.script,
637
651
  ) -> None:
638
652
  with yield_yaml_dict(PRE_COMMIT_CONFIG_YAML, modifications=modifications) as dict_:
639
- _add_pre_commit_config_repo(dict_, ACTIONS_URL, "conformalize-repo")
653
+ _add_pre_commit_config_repo(dict_, ACTIONS_URL, CONFORMALIZE_REPO_SUB_CMD)
640
654
  _add_pre_commit_config_repo(
641
655
  dict_, PRE_COMMIT_HOOKS_URL, "check-executables-have-shebangs"
642
656
  )
@@ -675,8 +689,12 @@ def add_pre_commit_config_yaml(
675
689
  types_or=["markdown", "yaml"],
676
690
  )
677
691
  if python:
678
- _add_pre_commit_config_repo(dict_, ACTIONS_URL, "format-requirements")
679
- _add_pre_commit_config_repo(dict_, ACTIONS_URL, "replace-sequence-strs")
692
+ _add_pre_commit_config_repo(dict_, ACTIONS_URL, FORMAT_REQUIREMENTS_SUB_CMD)
693
+ _add_pre_commit_config_repo(
694
+ dict_, ACTIONS_URL, REPLACE_SEQUENCE_STRS_SUB_CMD
695
+ )
696
+ _add_pre_commit_config_repo(dict_, ACTIONS_URL, TOUCH_EMPTY_PY_SUB_CMD)
697
+ _add_pre_commit_config_repo(dict_, ACTIONS_URL, TOUCH_PY_TYPED_SUB_CMD)
680
698
  if ruff:
681
699
  _add_pre_commit_config_repo(
682
700
  dict_, RUFF_URL, "ruff-check", args=("add", ["--fix"])
@@ -730,11 +748,11 @@ def _add_pre_commit_config_repo(
730
748
  args: tuple[Literal["add", "exact"], list[str]] | None = None,
731
749
  ) -> None:
732
750
  repos_list = get_list(pre_commit_dict, "repos")
733
- repo_dict = ensure_contains_partial(
751
+ repo_dict = ensure_contains_partial_dict(
734
752
  repos_list, {"repo": url}, extra={} if url == "local" else {"rev": "master"}
735
753
  )
736
754
  hooks_list = get_list(repo_dict, "hooks")
737
- hook_dict = ensure_contains_partial(hooks_list, {"id": id_})
755
+ hook_dict = ensure_contains_partial_dict(hooks_list, {"id": id_})
738
756
  if name is not None:
739
757
  hook_dict["name"] = name
740
758
  if entry is not None:
@@ -785,12 +803,13 @@ def add_pyproject_toml(
785
803
  project.setdefault("version", "0.1.0")
786
804
  dependency_groups = get_table(doc, "dependency-groups")
787
805
  dev = get_array(dependency_groups, "dev")
788
- ensure_contains(dev, "dycw-utilities[test]")
789
- ensure_contains(dev, "rich")
806
+ _ = ensure_contains_partial_str(dev, "dycw-utilities[test]")
807
+ _ = ensure_contains_partial_str(dev, "pyright")
808
+ _ = ensure_contains_partial_str(dev, "rich")
790
809
  if optional_dependencies__scripts:
791
810
  optional_dependencies = get_table(project, "optional-dependencies")
792
811
  scripts = get_array(optional_dependencies, "scripts")
793
- ensure_contains(scripts, "click >=8.3.1")
812
+ _ = ensure_contains_partial_str(scripts, "click")
794
813
  if python_package_name is not None:
795
814
  tool = get_table(doc, "tool")
796
815
  uv = get_table(tool, "uv")
@@ -921,13 +940,15 @@ def add_readme_md(
921
940
  name: str | None = SETTINGS.package_name,
922
941
  description: str | None = SETTINGS.description,
923
942
  ) -> None:
924
- with yield_text_file(README_MD, modifications=modifications) as temp:
943
+ with yield_text_file(README_MD, modifications=modifications) as context:
925
944
  lines: list[str] = []
926
945
  if name is not None:
927
946
  lines.append(f"# `{name}`")
928
947
  if description is not None:
929
948
  lines.append(description)
930
- _ = temp.write_text("\n\n".join(lines))
949
+ text = "\n\n".join(lines)
950
+ if search(escape(text), context.output, flags=MULTILINE) is None:
951
+ context.output += f"\n\n{text}"
931
952
 
932
953
 
933
954
  ##
@@ -1029,112 +1050,6 @@ def check_versions() -> None:
1029
1050
  ##
1030
1051
 
1031
1052
 
1032
- def ensure_aot_contains(array: AoT, /, *tables: Table) -> None:
1033
- for table_ in tables:
1034
- if table_ not in array:
1035
- array.append(table_)
1036
-
1037
-
1038
- def ensure_contains(array: HasAppend, /, *objs: Any) -> None:
1039
- if isinstance(array, AoT):
1040
- msg = f"Use {ensure_aot_contains.__name__!r} instead of {ensure_contains.__name__!r}"
1041
- raise TypeError(msg)
1042
- for obj in objs:
1043
- if obj not in array:
1044
- array.append(obj)
1045
-
1046
-
1047
- def ensure_contains_partial(
1048
- container: HasAppend, partial: StrDict, /, *, extra: StrDict | None = None
1049
- ) -> StrDict:
1050
- try:
1051
- return get_partial_dict(container, partial, skip_log=True)
1052
- except OneEmptyError:
1053
- dict_ = partial | ({} if extra is None else extra)
1054
- container.append(dict_)
1055
- return dict_
1056
-
1057
-
1058
- def ensure_not_contains(array: Array, /, *objs: Any) -> None:
1059
- for obj in objs:
1060
- try:
1061
- index = next(i for i, o in enumerate(array) if o == obj)
1062
- except StopIteration:
1063
- pass
1064
- else:
1065
- del array[index]
1066
-
1067
-
1068
- ##
1069
-
1070
-
1071
- def get_aot(container: HasSetDefault, key: str, /) -> AoT:
1072
- return ensure_class(container.setdefault(key, aot()), AoT)
1073
-
1074
-
1075
- def get_array(container: HasSetDefault, key: str, /) -> Array:
1076
- return ensure_class(container.setdefault(key, array()), Array)
1077
-
1078
-
1079
- def get_dict(container: HasSetDefault, key: str, /) -> StrDict:
1080
- return ensure_class(container.setdefault(key, {}), dict)
1081
-
1082
-
1083
- def get_list(container: HasSetDefault, key: str, /) -> list[Any]:
1084
- return ensure_class(container.setdefault(key, []), list)
1085
-
1086
-
1087
- def get_table(container: HasSetDefault, key: str, /) -> Table:
1088
- return ensure_class(container.setdefault(key, table()), Table)
1089
-
1090
-
1091
- ##
1092
-
1093
-
1094
- def get_partial_dict(
1095
- iterable: Iterable[Any], dict_: StrDict, /, *, skip_log: bool = False
1096
- ) -> StrDict:
1097
- try:
1098
- return one(i for i in iterable if is_partial_dict(dict_, i))
1099
- except OneEmptyError:
1100
- if not skip_log:
1101
- LOGGER.exception(
1102
- "Expected %s to contain %s (as a partial)",
1103
- pretty_repr(iterable),
1104
- pretty_repr(dict_),
1105
- )
1106
- raise
1107
- except OneNonUniqueError as error:
1108
- LOGGER.exception(
1109
- "Expected %s to contain %s uniquely (as a partial); got %s, %s and perhaps more",
1110
- pretty_repr(iterable),
1111
- pretty_repr(dict_),
1112
- pretty_repr(error.first),
1113
- pretty_repr(error.second),
1114
- )
1115
- raise
1116
-
1117
-
1118
- def is_partial_dict(obj: Any, dict_: StrDict, /) -> bool:
1119
- if not isinstance(obj, dict):
1120
- return False
1121
- results: dict[str, bool] = {}
1122
- for key, obj_value in obj.items():
1123
- try:
1124
- dict_value = dict_[key]
1125
- except KeyError:
1126
- results[key] = False
1127
- else:
1128
- if isinstance(obj_value, dict) and isinstance(dict_value, dict):
1129
- results[key] = is_partial_dict(obj_value, dict_value)
1130
- else:
1131
- results[key] = obj_value == dict_value
1132
- return all(results.values())
1133
-
1134
-
1135
- ##
1136
-
1137
-
1138
1053
  def get_python_package_name(
1139
1054
  *,
1140
1055
  package_name: str | None = SETTINGS.package_name,
@@ -1168,12 +1083,12 @@ def get_version_from_bumpversion_toml(
1168
1083
 
1169
1084
 
1170
1085
  def get_version_from_git_show() -> Version:
1171
- text = run("git", "show", f"origin/master:{BUMPVERSION_TOML}", return_=True)
1086
+ text = logged_run("git", "show", f"origin/master:{BUMPVERSION_TOML}", return_=True)
1172
1087
  return get_version_from_bumpversion_toml(obj=text.rstrip("\n"))
1173
1088
 
1174
1089
 
1175
1090
  def get_version_from_git_tag() -> Version:
1176
- text = run("git", "tag", "--points-at", "origin/master", return_=True)
1091
+ text = logged_run("git", "tag", "--points-at", "origin/master", return_=True)
1177
1092
  for line in text.splitlines():
1178
1093
  with suppress(ParseVersionError):
1179
1094
  return parse_version(line)
@@ -1210,25 +1125,19 @@ def run_bump_my_version(*, modifications: MutableSet[Path] | None = None) -> Non
1210
1125
 
1211
1126
  def run_pre_commit_update(*, modifications: MutableSet[Path] | None = None) -> None:
1212
1127
  cache = xdg_cache_home() / "conformalize" / get_repo_root().name
1213
-
1214
- def run_autoupdate() -> None:
1215
- current = PRE_COMMIT_CONFIG_YAML.read_text()
1216
- run("pre-commit", "autoupdate", print=True)
1217
- with writer(cache, overwrite=True) as temp:
1218
- _ = temp.write_text(get_now().format_iso())
1219
- if (modifications is not None) and (
1220
- PRE_COMMIT_CONFIG_YAML.read_text() != current
1221
- ):
1222
- modifications.add(PRE_COMMIT_CONFIG_YAML)
1223
-
1224
1128
  try:
1225
1129
  text = cache.read_text()
1226
1130
  except FileNotFoundError:
1227
- run_autoupdate()
1131
+ ...
1228
1132
  else:
1229
1133
  prev = ZonedDateTime.parse_iso(text.rstrip("\n"))
1230
- if prev < (get_now() - 12 * HOUR):
1231
- run_autoupdate()
1134
+ if prev >= (get_now() - 12 * HOUR):
1135
+ return
1136
+ write_text(cache, get_now().format_iso())
1137
+ current = PRE_COMMIT_CONFIG_YAML.read_text()
1138
+ logged_run("pre-commit", "autoupdate", print=True)
1139
+ if (modifications is not None) and (PRE_COMMIT_CONFIG_YAML.read_text() != current):
1140
+ modifications.add(PRE_COMMIT_CONFIG_YAML)
1232
1141
 
1233
1142
 
1234
1143
  ##
@@ -1247,22 +1156,21 @@ def run_ripgrep_and_replace(
1247
1156
  )
1248
1157
  if result is None:
1249
1158
  return
1250
- for path in map(Path, result.splitlines()):
1251
- with yield_text_file(path, modifications=modifications) as temp:
1252
- text = sub(
1159
+ for path in result.splitlines():
1160
+ with yield_text_file(path, modifications=modifications) as context:
1161
+ context.output = sub(
1253
1162
  r'# requires-python = ">=\d+\.\d+"',
1254
1163
  rf'# requires-python = ">={version}"',
1255
- path.read_text(),
1164
+ context.input,
1256
1165
  flags=MULTILINE,
1257
1166
  )
1258
- _ = temp.write_text(text)
1259
1167
 
1260
1168
 
1261
1169
  ##
1262
1170
 
1263
1171
 
1264
1172
  def set_version(version: Version, /) -> None:
1265
- run(
1173
+ logged_run(
1266
1174
  "bump-my-version",
1267
1175
  "replace",
1268
1176
  "--new-version",
@@ -1318,35 +1226,6 @@ def update_action_versions(*, modifications: MutableSet[Path] | None = None) ->
1318
1226
  ##
1319
1227
 
1320
1228
 
1321
- def write_text(
1322
- verb: str,
1323
- src: PathLike,
1324
- dest: PathLike,
1325
- /,
1326
- *,
1327
- modifications: MutableSet[Path] | None = None,
1328
- ) -> None:
1329
- src, dest = map(Path, [src, dest])
1330
- LOGGER.info("%s '%s'...", verb, dest)
1331
- text = src.read_text().rstrip("\n") + "\n"
1332
- with writer(dest, overwrite=True) as temp:
1333
- _ = temp.write_text(text)
1334
- if modifications is not None:
1335
- modifications.add(dest)
1336
-
1337
-
1338
- ##
1339
-
1340
-
1341
- def yaml_dump(obj: Any, /) -> str:
1342
- stream = StringIO()
1343
- YAML_INSTANCE.dump(obj, stream)
1344
- return stream.getvalue()
1345
-
1346
-
1347
- ##
1348
-
1349
-
1350
1229
  @contextmanager
1351
1230
  def yield_bumpversion_toml(
1352
1231
  *, modifications: MutableSet[Path] | None = None
@@ -1362,19 +1241,6 @@ def yield_bumpversion_toml(
1362
1241
  ##
1363
1242
 
1364
1243
 
1365
- @contextmanager
1366
- def yield_json_dict(
1367
- path: PathLike, /, *, modifications: MutableSet[Path] | None = None
1368
- ) -> Iterator[StrDict]:
1369
- with yield_write_context(
1370
- path, json.loads, dict, json.dumps, modifications=modifications
1371
- ) as dict_:
1372
- yield dict_
1373
-
1374
-
1375
- ##
1376
-
1377
-
1378
1244
  def yield_python_versions(
1379
1245
  version: str, /, *, max_: str = MAX_PYTHON_VERSION
1380
1246
  ) -> Iterator[str]:
@@ -1398,83 +1264,6 @@ def _yield_python_version_tuple(version: str, /) -> tuple[int, int]:
1398
1264
  ##
1399
1265
 
1400
1266
 
1401
- @contextmanager
1402
- def yield_text_file(
1403
- path: PathLike, /, *, modifications: MutableSet[Path] | None = None
1404
- ) -> Iterator[Path]:
1405
- path = Path(path)
1406
- try:
1407
- current = path.read_text()
1408
- except FileNotFoundError:
1409
- with TemporaryFile() as temp:
1410
- yield temp
1411
- write_text("Writing", temp, path, modifications=modifications)
1412
- else:
1413
- with TemporaryFile(text=current) as temp:
1414
- yield temp
1415
- if temp.read_text().rstrip("\n") != current.rstrip("\n"):
1416
- write_text("Writing", temp, path, modifications=modifications)
1417
-
1418
-
1419
- ##
1420
-
1421
-
1422
- @contextmanager
1423
- def yield_toml_doc(
1424
- path: PathLike, /, *, modifications: MutableSet[Path] | None = None
1425
- ) -> Iterator[TOMLDocument]:
1426
- with yield_write_context(
1427
- path, tomlkit.parse, document, tomlkit.dumps, modifications=modifications
1428
- ) as doc:
1429
- yield doc
1430
-
1431
-
1432
- ##
1433
-
1434
-
1435
- @contextmanager
1436
- def yield_write_context[T](
1437
- path: PathLike,
1438
- loads: Callable[[str], T],
1439
- get_default: Callable[[], T],
1440
- dumps: Callable[[T], str],
1441
- /,
1442
- *,
1443
- modifications: MutableSet[Path] | None = None,
1444
- ) -> Iterator[T]:
1445
- path = Path(path)
1446
-
1447
- def run_write(verb: str, data: T, /) -> None:
1448
- with writer(path, overwrite=True) as temp:
1449
- _ = temp.write_text(dumps(data))
1450
- write_text(verb, temp, path, modifications=modifications)
1451
-
1452
- try:
1453
- current = path.read_text()
1454
- except FileNotFoundError:
1455
- yield (default := get_default())
1456
- run_write("Writing", default)
1457
- else:
1458
- data = loads(current)
1459
- yield data
1460
- is_equal = data == loads(current) # tomlkit cannot handle !=
1461
- if not is_equal:
1462
- run_write("Modifying", data)
1463
-
1464
-
1465
- ##
1466
-
1467
-
1468
- @contextmanager
1469
- def yield_yaml_dict(
1470
- path: PathLike, /, *, modifications: MutableSet[Path] | None = None
1471
- ) -> Iterator[StrDict]:
1472
- with yield_write_context(
1473
- path, YAML_INSTANCE.load, dict, yaml_dump, modifications=modifications
1474
- ) as dict_:
1475
- yield dict_
1476
-
1477
-
1478
1267
  __all__ = [
1479
1268
  "add_bumpversion_toml",
1480
1269
  "add_coveragerc_toml",
@@ -1489,34 +1278,16 @@ __all__ = [
1489
1278
  "add_readme_md",
1490
1279
  "add_ruff_toml",
1491
1280
  "check_versions",
1492
- "ensure_aot_contains",
1493
- "ensure_contains",
1494
- "ensure_contains_partial",
1495
- "ensure_not_contains",
1496
- "get_aot",
1497
- "get_array",
1498
- "get_dict",
1499
- "get_list",
1500
- "get_partial_dict",
1501
1281
  "get_python_package_name",
1502
- "get_table",
1503
1282
  "get_version_from_bumpversion_toml",
1504
1283
  "get_version_from_git_show",
1505
1284
  "get_version_from_git_tag",
1506
- "is_partial_dict",
1507
1285
  "run_bump_my_version",
1508
1286
  "run_pre_commit_update",
1509
1287
  "run_ripgrep_and_replace",
1510
1288
  "set_version",
1511
1289
  "update_action_file_extensions",
1512
1290
  "update_action_versions",
1513
- "write_text",
1514
- "yaml_dump",
1515
1291
  "yield_bumpversion_toml",
1516
- "yield_json_dict",
1517
1292
  "yield_python_versions",
1518
- "yield_text_file",
1519
- "yield_toml_doc",
1520
- "yield_write_context",
1521
- "yield_yaml_dict",
1522
1293
  ]
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typed_settings import load_settings, option, settings
4
4
 
5
- from actions.conformalize_repo.constants import RUN_VERSION_BUMP
5
+ from actions.pre_commit.conformalize_repo.constants import RUN_VERSION_BUMP
6
6
  from actions.utilities import LOADER
7
7
 
8
8
 
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ from actions.constants import PATH_ACTIONS
4
+
5
+ PATH_PRE_COMMIT = PATH_ACTIONS / "pre_commit"
6
+
7
+
8
+ __all__ = ["PATH_PRE_COMMIT"]
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from utilities.logging import basic_config
6
+ from utilities.os import is_pytest
7
+
8
+ from actions.logging import LOGGER
9
+ from actions.pre_commit.click import path_argument
10
+ from actions.pre_commit.format_requirements.lib import format_requirements
11
+
12
+ if TYPE_CHECKING:
13
+ from pathlib import Path
14
+
15
+
16
+ @path_argument
17
+ def format_requirements_sub_cmd(*, paths: tuple[Path, ...]) -> None:
18
+ if is_pytest():
19
+ return
20
+ basic_config(obj=LOGGER)
21
+ format_requirements(*paths)
22
+
23
+
24
+ __all__ = ["format_requirements_sub_cmd"]
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ FORMAT_REQUIREMENTS_DOCSTRING = "Format a set of requirements"
4
+ FORMAT_REQUIREMENTS_SUB_CMD = "format-requirements"
5
+
6
+
7
+ __all__ = ["FORMAT_REQUIREMENTS_DOCSTRING", "FORMAT_REQUIREMENTS_SUB_CMD"]
@@ -0,0 +1,52 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from typing import TYPE_CHECKING
5
+
6
+ from utilities.text import repr_str, strip_and_dedent
7
+
8
+ from actions import __version__
9
+ from actions.logging import LOGGER
10
+ from actions.pre_commit.utilities import get_pyproject_dependencies, yield_toml_doc
11
+
12
+ if TYPE_CHECKING:
13
+ from collections.abc import MutableSet
14
+ from pathlib import Path
15
+
16
+ from utilities.packaging import Requirement
17
+ from utilities.types import PathLike
18
+
19
+
20
+ def format_requirements(*paths: PathLike) -> None:
21
+ LOGGER.info(
22
+ strip_and_dedent("""
23
+ Running '%s' (version %s) with settings:
24
+ - paths = %s
25
+ """),
26
+ format_requirements.__name__,
27
+ __version__,
28
+ paths,
29
+ )
30
+ modifications: set[Path] = set()
31
+ for path in paths:
32
+ _format_path(path, modifications=modifications)
33
+ if len(modifications) >= 1:
34
+ LOGGER.info(
35
+ "Exiting due to modifications: %s",
36
+ ", ".join(map(repr_str, sorted(modifications))),
37
+ )
38
+ sys.exit(1)
39
+
40
+
41
+ def _format_path(
42
+ path: PathLike, /, *, modifications: MutableSet[Path] | None = None
43
+ ) -> None:
44
+ with yield_toml_doc(path, modifications=modifications) as doc:
45
+ get_pyproject_dependencies(doc).apply(_format_req)
46
+
47
+
48
+ def _format_req(requirement: Requirement, /) -> Requirement:
49
+ return requirement
50
+
51
+
52
+ __all__ = ["format_requirements"]
@@ -0,0 +1 @@
1
+ from __future__ import annotations