dycw-pre-commit-hooks 0.11.1__tar.gz → 0.11.3__tar.gz

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.

Potentially problematic release.


This version of dycw-pre-commit-hooks might be problematic. Click here for more details.

Files changed (21) hide show
  1. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/PKG-INFO +3 -2
  2. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/pyproject.toml +18 -6
  3. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/__init__.py +1 -1
  4. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/common.py +1 -1
  5. dycw_pre_commit_hooks-0.11.3/src/pre_commit_hooks/format_requirements/__init__.py +109 -0
  6. dycw_pre_commit_hooks-0.11.3/src/pre_commit_hooks/format_requirements/__main__.py +6 -0
  7. dycw_pre_commit_hooks-0.11.3/src/tests/format_requirements/__init__.py +0 -0
  8. dycw_pre_commit_hooks-0.11.3/src/tests/format_requirements/in.toml +30 -0
  9. dycw_pre_commit_hooks-0.11.3/src/tests/format_requirements/out.toml +30 -0
  10. dycw_pre_commit_hooks-0.11.3/src/tests/format_requirements/test_format_requirements.py +15 -0
  11. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/.gitignore +0 -0
  12. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/README.md +0 -0
  13. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/py.typed +0 -0
  14. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/replace_sequence_str/__init__.py +0 -0
  15. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/replace_sequence_str/__main__.py +0 -0
  16. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/run_bump_my_version/__init__.py +0 -0
  17. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/run_bump_my_version/__main__.py +0 -0
  18. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/run_ruff_format/__init__.py +0 -0
  19. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/pre_commit_hooks/run_ruff_format/__main__.py +0 -0
  20. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/tests/__init__.py +0 -0
  21. {dycw_pre_commit_hooks-0.11.1 → dycw_pre_commit_hooks-0.11.3}/src/tests/test_main.py +0 -0
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-pre-commit-hooks
3
- Version: 0.11.1
3
+ Version: 0.11.3
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: click<8.3,>=8.2.1
7
- Requires-Dist: dycw-utilities<0.126,>=0.125.10
7
+ Requires-Dist: dycw-utilities<0.151,>=0.150.11
8
8
  Requires-Dist: libcst<1.9,>=1.8.2
9
9
  Requires-Dist: loguru<0.8,>=0.7.3
10
+ Requires-Dist: packaging<25.1,>=25.0
10
11
  Requires-Dist: tomlkit<0.14,>=0.13.2
11
12
  Description-Content-Type: text/markdown
12
13
 
@@ -9,7 +9,8 @@ requires = ["hatchling"]
9
9
  [dependency-groups]
10
10
  dev = [
11
11
  "dycw-utilities[test]",
12
- "pyright[nodejs]>=1.1.401",
12
+ "pyright[nodejs]",
13
+ "rich",
13
14
  ]
14
15
 
15
16
  # project
@@ -17,17 +18,19 @@ dev = [
17
18
  authors = [{name = "Derek Wan", email = "d.wan@icloud.com"}]
18
19
  dependencies = [
19
20
  "click >= 8.2.1, < 8.3",
20
- "dycw-utilities >= 0.125.10, < 0.126",
21
+ "dycw-utilities >= 0.150.11, < 0.151",
21
22
  "libcst >= 1.8.2, < 1.9",
22
23
  "loguru >= 0.7.3, < 0.8",
24
+ "packaging >= 25.0, < 25.1",
23
25
  "tomlkit >= 0.13.2, < 0.14",
24
26
  ]
25
27
  name = "dycw-pre-commit-hooks"
26
28
  readme = "README.md"
27
29
  requires-python = ">= 3.12"
28
- version = "0.11.1"
30
+ version = "0.11.3"
29
31
 
30
32
  [project.scripts]
33
+ format-requirements = "pre_commit_hooks.format_requirements:main"
31
34
  replace-sequence-str = "pre_commit_hooks.replace_sequence_str:main"
32
35
  run-bump-my-version = "pre_commit_hooks.run_bump_my_version:main"
33
36
  run-ruff-format = "pre_commit_hooks.run_ruff_format:main"
@@ -35,7 +38,7 @@ run-ruff-format = "pre_commit_hooks.run_ruff_format:main"
35
38
  # bump-my-version
36
39
  [tool.bumpversion]
37
40
  allow_dirty = true
38
- current_version = "0.11.1"
41
+ current_version = "0.11.3"
39
42
 
40
43
  [[tool.bumpversion.files]]
41
44
  filename = "src/pre_commit_hooks/__init__.py"
@@ -111,9 +114,12 @@ addopts = [
111
114
  "-ra",
112
115
  "-vv",
113
116
  "--color=auto",
114
- "--strict-markers",
115
117
  "--pdbcls=pudb.debugger:Debugger",
118
+ "--strict-markers",
116
119
  ]
120
+ asyncio_default_fixture_loop_scope = "function"
121
+ asyncio_mode = "auto"
122
+ collect_imported_tests = false
117
123
  filterwarnings = ["error"]
118
124
  minversion = "8.0"
119
125
  testpaths = ["src/tests"]
@@ -146,6 +152,7 @@ ignore = [
146
152
  "D107", # undocumented-public-init
147
153
  "D203", # one-blank-line-before-class
148
154
  "D213", # multi-line-summary-second-line
155
+ "DOC", # pydoclint
149
156
  "E501", # line-too-long
150
157
  "PD", # pandas-vet
151
158
  "PERF203", # try-except-in-loop
@@ -155,6 +162,7 @@ ignore = [
155
162
  "PLR0913", # too-many-arguments
156
163
  "PLR0915", # too-many-statements
157
164
  "PLR2004", # magic-value-comparison
165
+ "PT012", # pytest-raises-with-multiple-statements
158
166
  "PT013", # pytest-incorrect-pytest-import
159
167
  "S311", # suspicious-non-cryptographic-random-usage
160
168
  "S603", # subprocess-without-shell-equals-true
@@ -177,7 +185,11 @@ ignore = [
177
185
  "ISC001", # single-line-implicit-string-concatenation
178
186
  "ISC002", # multi-line-implicit-string-concatenation
179
187
  ]
180
- select = ["ALL"]
188
+ preview = true
189
+ select = [
190
+ "ALL",
191
+ "RUF022", # unsorted-dunder-all
192
+ ]
181
193
 
182
194
  [tool.ruff.lint.extend-per-file-ignores]
183
195
  "*.ipynb" = [
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.11.1"
3
+ __version__ = "0.11.3"
@@ -4,7 +4,7 @@ from dataclasses import dataclass
4
4
 
5
5
  from loguru import logger
6
6
  from tomlkit import TOMLDocument, parse
7
- from utilities.git import get_repo_root
7
+ from utilities.pathlib import get_repo_root
8
8
 
9
9
  _ROOT = get_repo_root()
10
10
  PYPROJECT_TOML = _ROOT.joinpath("pyproject.toml")
@@ -0,0 +1,109 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, override
4
+
5
+ from click import argument, command
6
+ from packaging._tokenizer import ParserSyntaxError
7
+ from packaging.requirements import (
8
+ InvalidRequirement,
9
+ Requirement,
10
+ _parse_requirement, # pyright: ignore[reportPrivateImportUsage]
11
+ )
12
+ from packaging.specifiers import Specifier, SpecifierSet
13
+ from tomlkit import array, dumps, loads, string
14
+ from tomlkit.items import Array, Table
15
+ from utilities.atomicwrites import writer
16
+ from utilities.click import FilePath
17
+
18
+ from pre_commit_hooks.common import PYPROJECT_TOML
19
+
20
+ if TYPE_CHECKING:
21
+ from collections.abc import Iterator
22
+ from pathlib import Path
23
+
24
+ from tomlkit.toml_document import TOMLDocument
25
+
26
+
27
+ @command()
28
+ @argument("paths", nargs=-1, type=FilePath)
29
+ def main(*, paths: tuple[Path, ...]) -> bool:
30
+ """CLI for the `format_requirements` hook."""
31
+ results = list(map(_process, paths))
32
+ return all(results)
33
+
34
+
35
+ def _process(path: Path, /) -> bool:
36
+ doc = loads(path.read_text())
37
+ expected = _format_path(path)
38
+ if doc == expected:
39
+ return True
40
+ with writer(path, overwrite=True) as temp:
41
+ _ = temp.write_text(dumps(expected))
42
+ return False
43
+
44
+
45
+ def _format_path(path: Path, /) -> TOMLDocument:
46
+ doc = loads(path.read_text())
47
+ if isinstance(dep_grps := doc.get("dependency-groups"), Table):
48
+ for key, value in dep_grps.items():
49
+ if isinstance(value, Array):
50
+ dep_grps[key] = _format_array(value)
51
+ if isinstance(project := doc["project"], Table):
52
+ if isinstance(deps := project["dependencies"], Array):
53
+ project["dependencies"] = _format_array(deps)
54
+ if isinstance(optional := project.get("optional-dependencies"), Table):
55
+ for key, value in optional.items():
56
+ if isinstance(value, Array):
57
+ optional[key] = _format_array(value)
58
+ return doc
59
+
60
+
61
+ def _format_array(dependencies: Array, /) -> Array:
62
+ new = array().multiline(multiline=True)
63
+ new.extend(map(_format_item, dependencies))
64
+ return new
65
+
66
+
67
+ def _format_item(item: Any, /) -> Any:
68
+ if not isinstance(item, str):
69
+ return item
70
+ return string(str(_CustomRequirement(item)))
71
+
72
+
73
+ class _CustomRequirement(Requirement):
74
+ @override
75
+ def __init__(self, requirement_string: str) -> None:
76
+ super().__init__(requirement_string)
77
+ try:
78
+ parsed = _parse_requirement(requirement_string)
79
+ except ParserSyntaxError as e:
80
+ raise InvalidRequirement(str(e)) from e
81
+ self.specifier = _CustomSpecifierSet(parsed.specifier)
82
+
83
+ @override
84
+ def _iter_parts(self, name: str) -> Iterator[str]:
85
+ yield name
86
+ if self.extras:
87
+ formatted_extras = ",".join(sorted(self.extras))
88
+ yield f"[{formatted_extras}]"
89
+ if self.specifier:
90
+ yield f" {self.specifier}"
91
+ if self.url:
92
+ yield f"@ {self.url}"
93
+ if self.marker:
94
+ yield " "
95
+ if self.marker:
96
+ yield f"; {self.marker}"
97
+
98
+
99
+ class _CustomSpecifierSet(SpecifierSet):
100
+ @override
101
+ def __str__(self) -> str:
102
+ specs = sorted(self._specs, key=self._key)
103
+ return ", ".join(map(str, specs))
104
+
105
+ def _key(self, spec: Specifier, /) -> int:
106
+ return [">=", "<"].index(spec.operator)
107
+
108
+
109
+ __all__ = ["PYPROJECT_TOML", "main"]
@@ -0,0 +1,6 @@
1
+ from __future__ import annotations
2
+
3
+ from pre_commit_hooks.format_requirements import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(int(not main()))
@@ -0,0 +1,30 @@
1
+ [dependency-groups]
2
+ group = [
3
+ "unbounded",
4
+ "lower>=1.2.3",
5
+ "upper<1.3",
6
+ "lower-and-upper1>=1.2.3,<1.3",
7
+ ]
8
+
9
+ [project]
10
+ dependencies = [
11
+ "unbounded",
12
+ "lower1>=1.2.3",
13
+ "lower2 >= 1.2.3",
14
+ "upper1<1.3",
15
+ "upper2 < 1.3",
16
+ "lower-and-upper1>=1.2.3,<1.3",
17
+ "lower-and-upper2<1.3,>=1.2.3",
18
+ "lower-and-upper3 >= 1.2.3 , <1.3",
19
+ "with-extra[extra]",
20
+ "with-extra[extra]>=1.2.3",
21
+ "with-extra[extra] >= 1.2.3",
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ group = [
26
+ "unbounded",
27
+ "lower>=1.2.3",
28
+ "upper<1.3",
29
+ "lower-and-upper1>=1.2.3,<1.3",
30
+ ]
@@ -0,0 +1,30 @@
1
+ [dependency-groups]
2
+ group = [
3
+ "unbounded",
4
+ "lower >=1.2.3",
5
+ "upper <1.3",
6
+ "lower-and-upper1 >=1.2.3, <1.3",
7
+ ]
8
+
9
+ [project]
10
+ dependencies = [
11
+ "unbounded",
12
+ "lower1 >=1.2.3",
13
+ "lower2 >=1.2.3",
14
+ "upper1 <1.3",
15
+ "upper2 <1.3",
16
+ "lower-and-upper1 >=1.2.3, <1.3",
17
+ "lower-and-upper2 >=1.2.3, <1.3",
18
+ "lower-and-upper3 >=1.2.3, <1.3",
19
+ "with-extra[extra]",
20
+ "with-extra[extra] >=1.2.3",
21
+ "with-extra[extra] >=1.2.3",
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ group = [
26
+ "unbounded",
27
+ "lower >=1.2.3",
28
+ "upper <1.3",
29
+ "lower-and-upper1 >=1.2.3, <1.3",
30
+ ]
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from tomlkit import dumps
6
+
7
+ from pre_commit_hooks.format_requirements import _format_path
8
+
9
+
10
+ class TestFormatRequirements:
11
+ def test_basic(self) -> None:
12
+ root = Path(__file__).parent
13
+ result = dumps(_format_path(root.joinpath("in.toml")))
14
+ expected = root.joinpath("out.toml").read_text()
15
+ assert result == expected