dycw-pre-commit-hooks 0.12.8__py3-none-any.whl → 0.14.26__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 (37) hide show
  1. dycw_pre_commit_hooks-0.14.26.dist-info/METADATA +57 -0
  2. dycw_pre_commit_hooks-0.14.26.dist-info/RECORD +23 -0
  3. {dycw_pre_commit_hooks-0.12.8.dist-info → dycw_pre_commit_hooks-0.14.26.dist-info}/WHEEL +1 -1
  4. dycw_pre_commit_hooks-0.14.26.dist-info/entry_points.txt +14 -0
  5. pre_commit_hooks/__init__.py +1 -1
  6. pre_commit_hooks/configs/gitignore +243 -0
  7. pre_commit_hooks/constants.py +149 -0
  8. pre_commit_hooks/hooks/__init__.py +1 -0
  9. pre_commit_hooks/hooks/add_future_import_annotations.py +63 -0
  10. pre_commit_hooks/hooks/add_hooks.py +373 -0
  11. pre_commit_hooks/hooks/check_versions_consistent.py +42 -0
  12. pre_commit_hooks/hooks/format_pre_commit_config.py +70 -0
  13. pre_commit_hooks/hooks/format_requirements.py +56 -0
  14. pre_commit_hooks/{replace_sequence_str/__init__.py → hooks/replace_sequence_str.py} +25 -19
  15. pre_commit_hooks/hooks/run_prek_autoupdate.py +56 -0
  16. pre_commit_hooks/hooks/run_version_bump.py +53 -0
  17. pre_commit_hooks/hooks/setup_git.py +40 -0
  18. pre_commit_hooks/hooks/setup_pyright.py +82 -0
  19. pre_commit_hooks/hooks/setup_ruff.py +129 -0
  20. pre_commit_hooks/hooks/update_requirements.py +165 -0
  21. pre_commit_hooks/types.py +18 -0
  22. pre_commit_hooks/utilities.py +658 -0
  23. dycw_pre_commit_hooks-0.12.8.dist-info/METADATA +0 -46
  24. dycw_pre_commit_hooks-0.12.8.dist-info/RECORD +0 -19
  25. dycw_pre_commit_hooks-0.12.8.dist-info/entry_points.txt +0 -7
  26. pre_commit_hooks/check_submodules/__init__.py +0 -50
  27. pre_commit_hooks/check_submodules/__main__.py +0 -6
  28. pre_commit_hooks/common.py +0 -131
  29. pre_commit_hooks/format_requirements/__init__.py +0 -107
  30. pre_commit_hooks/format_requirements/__main__.py +0 -6
  31. pre_commit_hooks/mirror_files/__init__.py +0 -57
  32. pre_commit_hooks/mirror_files/__main__.py +0 -6
  33. pre_commit_hooks/replace_sequence_str/__main__.py +0 -6
  34. pre_commit_hooks/run_bump_my_version/__init__.py +0 -53
  35. pre_commit_hooks/run_bump_my_version/__main__.py +0 -6
  36. pre_commit_hooks/tag_commits/__init__.py +0 -103
  37. pre_commit_hooks/tag_commits/__main__.py +0 -6
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+ from subprocess import CalledProcessError
5
+ from typing import TYPE_CHECKING
6
+
7
+ from click import command
8
+ from utilities.click import CONTEXT_SETTINGS
9
+ from utilities.os import is_pytest
10
+ from utilities.version import Version3, Version3Error
11
+
12
+ from pre_commit_hooks.constants import BUMPVERSION_TOML, paths_argument
13
+ from pre_commit_hooks.utilities import (
14
+ get_version_from_git_show,
15
+ get_version_from_git_tag,
16
+ get_version_from_path,
17
+ run_all_maybe_raise,
18
+ run_bump_my_version,
19
+ )
20
+
21
+ if TYPE_CHECKING:
22
+ from pathlib import Path
23
+
24
+ from utilities.types import PathLike
25
+
26
+
27
+ @command(**CONTEXT_SETTINGS)
28
+ @paths_argument
29
+ def _main(*, paths: tuple[Path, ...]) -> None:
30
+ if is_pytest():
31
+ return
32
+ run_all_maybe_raise(*(partial(_run, path=p) for p in paths))
33
+
34
+
35
+ def _run(*, path: PathLike = BUMPVERSION_TOML) -> bool:
36
+ try:
37
+ prev = get_version_from_git_tag()
38
+ except (CalledProcessError, ValueError):
39
+ try:
40
+ prev = get_version_from_git_show(path=path)
41
+ except (CalledProcessError, KeyError, Version3Error):
42
+ run_bump_my_version(Version3(0, 1, 0), path=path)
43
+ return False
44
+ current = get_version_from_path(path=path)
45
+ patched = prev.bump_patch()
46
+ if current in {patched, prev.bump_minor(), prev.bump_major()}:
47
+ return True
48
+ run_bump_my_version(patched)
49
+ return False
50
+
51
+
52
+ if __name__ == "__main__":
53
+ _main()
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+ from pathlib import Path
5
+ from re import MULTILINE, escape, search
6
+ from typing import TYPE_CHECKING
7
+
8
+ from click import command
9
+ from utilities.click import CONTEXT_SETTINGS
10
+ from utilities.importlib import files
11
+ from utilities.os import is_pytest
12
+
13
+ from pre_commit_hooks.constants import GITIGNORE, paths_argument
14
+ from pre_commit_hooks.utilities import run_all_maybe_raise, yield_text_file
15
+
16
+ if TYPE_CHECKING:
17
+ from pathlib import Path
18
+
19
+ from utilities.types import PathLike
20
+
21
+
22
+ @command(**CONTEXT_SETTINGS)
23
+ @paths_argument
24
+ def _main(*, paths: tuple[Path, ...]) -> None:
25
+ if is_pytest():
26
+ return
27
+ run_all_maybe_raise(*(partial(_run, path=p.parent / GITIGNORE) for p in paths))
28
+
29
+
30
+ def _run(*, path: PathLike = GITIGNORE) -> bool:
31
+ modifications: set[Path] = set()
32
+ with yield_text_file(path, modifications=modifications) as context:
33
+ text = (files(anchor="pre_commit_hooks") / "configs/gitignore").read_text()
34
+ if search(escape(text), context.output, flags=MULTILINE) is None:
35
+ context.output += f"\n\n{text}"
36
+ return len(modifications) == 0
37
+
38
+
39
+ if __name__ == "__main__":
40
+ _main()
@@ -0,0 +1,82 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+ from typing import TYPE_CHECKING
5
+
6
+ from click import command
7
+ from utilities.click import CONTEXT_SETTINGS
8
+ from utilities.os import is_pytest
9
+
10
+ from pre_commit_hooks.constants import (
11
+ DEFAULT_PYTHON_VERSION,
12
+ PYRIGHTCONFIG_JSON,
13
+ paths_argument,
14
+ python_version_option,
15
+ )
16
+ from pre_commit_hooks.utilities import (
17
+ ensure_contains,
18
+ get_set_list_strs,
19
+ run_all_maybe_raise,
20
+ yield_json_dict,
21
+ )
22
+
23
+ if TYPE_CHECKING:
24
+ from pathlib import Path
25
+
26
+ from utilities.types import PathLike
27
+
28
+
29
+ @command(**CONTEXT_SETTINGS)
30
+ @paths_argument
31
+ @python_version_option
32
+ def _main(
33
+ *, paths: tuple[Path, ...], python_version: str = DEFAULT_PYTHON_VERSION
34
+ ) -> None:
35
+ if is_pytest():
36
+ return
37
+ run_all_maybe_raise(
38
+ *(
39
+ partial(
40
+ _run, path=p.parent / PYRIGHTCONFIG_JSON, python_version=python_version
41
+ )
42
+ for p in paths
43
+ )
44
+ )
45
+
46
+
47
+ def _run(
48
+ *, path: PathLike = PYRIGHTCONFIG_JSON, python_version: str = DEFAULT_PYTHON_VERSION
49
+ ) -> bool:
50
+ modifications: set[Path] = set()
51
+ with yield_json_dict(path, modifications=modifications) as dict_:
52
+ dict_["deprecateTypingAliases"] = True
53
+ dict_["enableReachabilityAnalysis"] = False
54
+ include = get_set_list_strs(dict_, "include")
55
+ ensure_contains(include, "src")
56
+ dict_["pythonVersion"] = python_version
57
+ dict_["reportCallInDefaultInitializer"] = True
58
+ dict_["reportImplicitOverride"] = True
59
+ dict_["reportImplicitStringConcatenation"] = True
60
+ dict_["reportImportCycles"] = True
61
+ dict_["reportMissingSuperCall"] = True
62
+ dict_["reportMissingTypeArgument"] = False
63
+ dict_["reportMissingTypeStubs"] = False
64
+ dict_["reportPrivateImportUsage"] = False
65
+ dict_["reportPrivateUsage"] = False
66
+ dict_["reportPropertyTypeMismatch"] = True
67
+ dict_["reportUninitializedInstanceVariable"] = True
68
+ dict_["reportUnknownArgumentType"] = False
69
+ dict_["reportUnknownMemberType"] = False
70
+ dict_["reportUnknownParameterType"] = False
71
+ dict_["reportUnknownVariableType"] = False
72
+ dict_["reportUnnecessaryComparison"] = False
73
+ dict_["reportUnnecessaryTypeIgnoreComment"] = True
74
+ dict_["reportUnusedCallResult"] = True
75
+ dict_["reportUnusedImport"] = False
76
+ dict_["reportUnusedVariable"] = False
77
+ dict_["typeCheckingMode"] = "strict"
78
+ return len(modifications) == 0
79
+
80
+
81
+ if __name__ == "__main__":
82
+ _main()
@@ -0,0 +1,129 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+ from typing import TYPE_CHECKING
5
+
6
+ from click import command
7
+ from utilities.click import CONTEXT_SETTINGS
8
+ from utilities.os import is_pytest
9
+
10
+ from pre_commit_hooks.constants import (
11
+ DEFAULT_PYTHON_VERSION,
12
+ RUFF_TOML,
13
+ paths_argument,
14
+ python_version_option,
15
+ )
16
+ from pre_commit_hooks.utilities import (
17
+ ensure_contains,
18
+ ensure_not_contains,
19
+ get_set_array,
20
+ get_set_table,
21
+ run_all_maybe_raise,
22
+ yield_toml_doc,
23
+ )
24
+
25
+ if TYPE_CHECKING:
26
+ from pathlib import Path
27
+
28
+ from utilities.types import PathLike
29
+
30
+
31
+ @command(**CONTEXT_SETTINGS)
32
+ @paths_argument
33
+ @python_version_option
34
+ def _main(
35
+ *, paths: tuple[Path, ...], python_version: str = DEFAULT_PYTHON_VERSION
36
+ ) -> None:
37
+ if is_pytest():
38
+ return
39
+ run_all_maybe_raise(
40
+ *(
41
+ partial(_run, path=p.parent / RUFF_TOML, python_version=python_version)
42
+ for p in paths
43
+ )
44
+ )
45
+
46
+
47
+ def _run(
48
+ *, path: PathLike = RUFF_TOML, python_version: str = DEFAULT_PYTHON_VERSION
49
+ ) -> bool:
50
+ modifications: set[Path] = set()
51
+ with yield_toml_doc(path, modifications=modifications) as doc:
52
+ doc["target-version"] = f"py{python_version.replace('.', '')}"
53
+ doc["unsafe-fixes"] = True
54
+ fmt = get_set_table(doc, "format")
55
+ fmt["preview"] = True
56
+ fmt["skip-magic-trailing-comma"] = True
57
+ lint = get_set_table(doc, "lint")
58
+ lint["explicit-preview-rules"] = True
59
+ fixable = get_set_array(lint, "fixable")
60
+ ensure_contains(fixable, "ALL")
61
+ ignore = get_set_array(lint, "ignore")
62
+ ensure_contains(
63
+ ignore,
64
+ "ANN401", # any-type
65
+ "ASYNC109", # async-function-with-timeout
66
+ "C901", # complex-structure
67
+ "CPY", # flake8-copyright
68
+ "D", # pydocstyle
69
+ "E501", # line-too-long
70
+ "PD", # pandas-vet
71
+ "PERF203", # try-except-in-loop
72
+ "PLC0415", # import-outside-top-level
73
+ "PLE1205", # logging-too-many-args
74
+ "PLR0904", # too-many-public-methods
75
+ "PLR0911", # too-many-return-statements
76
+ "PLR0912", # too-many-branches
77
+ "PLR0913", # too-many-arguments
78
+ "PLR0915", # too-many-statements
79
+ "PLR2004", # magic-value-comparison
80
+ "PT012", # pytest-raises-with-multiple-statements
81
+ "PT013", # pytest-incorrect-pytest-import
82
+ "PYI041", # redundant-numeric-union
83
+ "S202", # tarfile-unsafe-members
84
+ "S310", # suspicious-url-open-usage
85
+ "S311", # suspicious-non-cryptographic-random-usage
86
+ "S602", # subprocess-popen-with-shell-equals-true
87
+ "S603", # subprocess-without-shell-equals-true
88
+ "S607", # start-process-with-partial-path
89
+ # preview
90
+ "S101", # assert
91
+ # formatter
92
+ "W191", # tab-indentation
93
+ "E111", # indentation-with-invalid-multiple
94
+ "E114", # indentation-with-invalid-multiple-comment
95
+ "E117", # over-indented
96
+ "COM812", # missing-trailing-comma
97
+ "COM819", # prohibited-trailing-comma
98
+ "ISC001", # single-line-implicit-string-concatenation
99
+ "ISC002", # multi-line-implicit-string-concatenation
100
+ )
101
+ lint["preview"] = True
102
+ select = get_set_array(lint, "select")
103
+ selected_rules = [
104
+ "RUF022", # unsorted-dunder-all
105
+ "RUF029", # unused-async
106
+ ]
107
+ ensure_contains(select, "ALL", *selected_rules)
108
+ extend_per_file_ignores = get_set_table(lint, "extend-per-file-ignores")
109
+ test_py = get_set_array(extend_per_file_ignores, "test_*.py")
110
+ test_py_rules = [
111
+ "S101", # assert
112
+ "SLF001", # private-member-access
113
+ ]
114
+ ensure_contains(test_py, *test_py_rules)
115
+ ensure_not_contains(ignore, *selected_rules, *test_py_rules)
116
+ bugbear = get_set_table(lint, "flake8-bugbear")
117
+ extend_immutable_calls = get_set_array(bugbear, "extend-immutable-calls")
118
+ ensure_contains(extend_immutable_calls, "typing.cast")
119
+ tidy_imports = get_set_table(lint, "flake8-tidy-imports")
120
+ tidy_imports["ban-relative-imports"] = "all"
121
+ isort = get_set_table(lint, "isort")
122
+ req_imps = get_set_array(isort, "required-imports")
123
+ ensure_contains(req_imps, "from __future__ import annotations")
124
+ isort["split-on-trailing-comma"] = False
125
+ return len(modifications) == 0
126
+
127
+
128
+ if __name__ == "__main__":
129
+ _main()
@@ -0,0 +1,165 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING
6
+
7
+ from click import command, option
8
+ from utilities.click import CONTEXT_SETTINGS, ListStrs
9
+ from utilities.functions import max_nullable
10
+ from utilities.os import is_pytest
11
+ from utilities.subprocess import uv_pip_list
12
+ from utilities.version import Version2, Version2Or3, Version3, parse_version_2_or_3
13
+
14
+ from pre_commit_hooks.constants import PYPROJECT_TOML, paths_argument
15
+ from pre_commit_hooks.utilities import (
16
+ get_pyproject_dependencies,
17
+ run_all_maybe_raise,
18
+ yield_toml_doc,
19
+ )
20
+
21
+ if TYPE_CHECKING:
22
+ from pathlib import Path
23
+
24
+ from utilities.packaging import Requirement
25
+ from utilities.types import PathLike, StrDict
26
+
27
+
28
+ type Version1or2 = int | Version2
29
+ type VersionSet = dict[str, Version2Or3]
30
+
31
+
32
+ @command(**CONTEXT_SETTINGS)
33
+ @paths_argument
34
+ @option("--index", type=ListStrs(), default=None)
35
+ @option("--native-tls", is_flag=True, default=False)
36
+ def _main(
37
+ *, paths: tuple[Path, ...], index: list[str] | None = None, native_tls: bool = False
38
+ ) -> None:
39
+ if is_pytest():
40
+ return
41
+ versions = _get_versions(index=index, native_tls=native_tls)
42
+ run_all_maybe_raise(
43
+ *(
44
+ partial(_run, path=p, versions=versions, index=index, native_tls=native_tls)
45
+ for p in paths
46
+ )
47
+ )
48
+
49
+
50
+ def _get_versions(
51
+ *, index: list[str] | None = None, native_tls: bool = False
52
+ ) -> dict[str, Version2Or3]:
53
+ out: StrDict = {}
54
+ for item in uv_pip_list(exclude_editable=True, index=index, native_tls=native_tls):
55
+ match item.version, item.latest_version:
56
+ case Version2(), Version2() | None:
57
+ out[item.name] = max_nullable([item.version, item.latest_version])
58
+ case Version3(), Version3() | None:
59
+ out[item.name] = max_nullable([item.version, item.latest_version])
60
+ case _:
61
+ raise TypeError(item.version, item.latest_version)
62
+ return out
63
+
64
+
65
+ def _run(
66
+ *,
67
+ path: PathLike = PYPROJECT_TOML,
68
+ versions: VersionSet | None = None,
69
+ index: list[str] | None = None,
70
+ native_tls: bool = False,
71
+ ) -> bool:
72
+ func = partial(_transform, versions=versions, index=index, native_tls=native_tls)
73
+ modifications: set[Path] = set()
74
+ with yield_toml_doc(path, modifications=modifications) as doc:
75
+ get_pyproject_dependencies(doc).map_requirements(func)
76
+ return len(modifications) == 0
77
+
78
+
79
+ def _transform(
80
+ requirement: Requirement,
81
+ /,
82
+ *,
83
+ versions: VersionSet | None = None,
84
+ index: list[str] | None = None,
85
+ native_tls: bool = False,
86
+ ) -> Requirement:
87
+ if versions is None:
88
+ versions_use = _get_versions(index=index, native_tls=native_tls)
89
+ else:
90
+ versions_use = versions
91
+ try:
92
+ lower = parse_version_2_or_3(requirement[">="])
93
+ except KeyError:
94
+ lower = None
95
+ try:
96
+ upper = _parse_version_1_or_2(requirement["<"])
97
+ except KeyError:
98
+ upper = None
99
+ try:
100
+ fixed = parse_version_2_or_3(requirement["=="])
101
+ except KeyError:
102
+ fixed = None
103
+ latest = versions_use.get(requirement.name)
104
+ new_lower: Version2Or3 | None = None
105
+ new_upper: Version1or2 | None = None
106
+ match lower, upper, fixed, latest:
107
+ case None, None, None, None:
108
+ pass
109
+ case None, None, Version2() | Version3(), Version2() | Version3() | None:
110
+ pass
111
+ case None, None, None, Version2() | Version3():
112
+ new_lower = latest
113
+ new_upper = latest.bump_major().major
114
+ case Version2() | Version3(), None, None, None:
115
+ new_lower = lower
116
+ case (Version2(), None, None, Version2()) | (
117
+ Version3(),
118
+ None,
119
+ None,
120
+ Version3(),
121
+ ):
122
+ new_lower = max(lower, latest)
123
+ case None, int() | Version2(), None, None:
124
+ new_upper = upper
125
+ case None, int(), None, Version2():
126
+ new_upper = max(upper, latest.bump_major().major)
127
+ case None, Version2(), None, Version3():
128
+ bumped = latest.bump_minor()
129
+ new_upper = max(upper, Version2(bumped.major, bumped.minor))
130
+ case (
131
+ (Version2(), int(), None, None)
132
+ | (Version3(), int(), None, None)
133
+ | (Version3(), Version2(), None, None)
134
+ ):
135
+ new_lower = lower
136
+ new_upper = upper
137
+ case (Version2(), int(), None, Version2()) | (
138
+ Version3(),
139
+ int(),
140
+ None,
141
+ Version3(),
142
+ ):
143
+ new_lower = max(lower, latest)
144
+ new_upper = new_lower.bump_major().major
145
+ case Version3(), Version2(), None, Version3():
146
+ new_lower = max(lower, latest)
147
+ new_upper = new_lower.bump_minor().version2
148
+ case never:
149
+ raise NotImplementedError(never)
150
+ if new_lower is not None:
151
+ requirement = requirement.replace(">=", str(new_lower))
152
+ if new_upper is not None:
153
+ requirement = requirement.replace("<", str(new_upper))
154
+ return requirement
155
+
156
+
157
+ def _parse_version_1_or_2(version: str, /) -> Version1or2:
158
+ try:
159
+ return int(version)
160
+ except ValueError:
161
+ return Version2.parse(version)
162
+
163
+
164
+ if __name__ == "__main__":
165
+ _main()
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+
5
+ from tomlkit.container import Container
6
+ from tomlkit.items import AoT, Array, Table
7
+ from utilities.packaging import Requirement
8
+ from utilities.types import StrDict
9
+
10
+ type ArrayLike = AoT | list[str] | list[StrDict]
11
+ type ContainerLike = Container | Table
12
+
13
+
14
+ type FuncRequirement = Callable[[Requirement], Requirement]
15
+ type TransformArray = Callable[[Array], None]
16
+
17
+
18
+ __all__ = ["ArrayLike", "ContainerLike", "FuncRequirement", "TransformArray"]