crackerjack 0.14.4__py3-none-any.whl → 0.14.6__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.
- crackerjack/.pre-commit-config.yaml +3 -3
- crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
- crackerjack/crackerjack.py +126 -60
- crackerjack/pyproject.toml +7 -5
- {crackerjack-0.14.4.dist-info → crackerjack-0.14.6.dist-info}/METADATA +3 -3
- {crackerjack-0.14.4.dist-info → crackerjack-0.14.6.dist-info}/RECORD +9 -8
- {crackerjack-0.14.4.dist-info → crackerjack-0.14.6.dist-info}/WHEEL +0 -0
- {crackerjack-0.14.4.dist-info → crackerjack-0.14.6.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.14.4.dist-info → crackerjack-0.14.6.dist-info}/licenses/LICENSE +0 -0
@@ -17,7 +17,7 @@ repos:
|
|
17
17
|
- id: check-added-large-files
|
18
18
|
name: check-added-large-files
|
19
19
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
20
|
-
rev: v0.
|
20
|
+
rev: v0.11.2
|
21
21
|
hooks:
|
22
22
|
- id: ruff-format
|
23
23
|
- id: ruff
|
@@ -65,11 +65,11 @@ repos:
|
|
65
65
|
- id: bandit
|
66
66
|
args: ["-c", "pyproject.toml"]
|
67
67
|
- repo: https://github.com/RobertCraigie/pyright-python
|
68
|
-
rev: v1.1.
|
68
|
+
rev: v1.1.397
|
69
69
|
hooks:
|
70
70
|
- id: pyright
|
71
71
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
72
|
-
rev: v0.
|
72
|
+
rev: v0.11.2
|
73
73
|
hooks:
|
74
74
|
- id: ruff
|
75
75
|
- id: ruff-format
|
Binary file
|
crackerjack/crackerjack.py
CHANGED
@@ -5,13 +5,13 @@ import subprocess
|
|
5
5
|
import tokenize
|
6
6
|
import typing as t
|
7
7
|
from contextlib import suppress
|
8
|
+
from dataclasses import dataclass, field
|
8
9
|
from pathlib import Path
|
9
10
|
from subprocess import CompletedProcess
|
10
11
|
from subprocess import run as execute
|
11
12
|
from token import STRING
|
12
13
|
from tomllib import loads
|
13
14
|
|
14
|
-
from pydantic import BaseModel
|
15
15
|
from rich.console import Console
|
16
16
|
from tomli_w import dumps
|
17
17
|
|
@@ -20,7 +20,8 @@ interactive_hooks = ("refurb", "bandit", "pyright")
|
|
20
20
|
default_python_version = "3.13"
|
21
21
|
|
22
22
|
|
23
|
-
|
23
|
+
@dataclass
|
24
|
+
class CodeCleaner:
|
24
25
|
console: Console
|
25
26
|
|
26
27
|
def clean_files(self, pkg_dir: Path | None) -> None:
|
@@ -35,20 +36,20 @@ class CodeCleaner(BaseModel, arbitrary_types_allowed=True):
|
|
35
36
|
def clean_file(self, file_path: Path) -> None:
|
36
37
|
try:
|
37
38
|
if file_path.resolve() == Path(__file__).resolve():
|
38
|
-
print(f"Skipping cleaning of {file_path} (self file).")
|
39
|
+
self.console.print(f"Skipping cleaning of {file_path} (self file).")
|
39
40
|
return
|
40
41
|
except Exception as e:
|
41
|
-
print(f"Error comparing file paths: {e}")
|
42
|
+
self.console.print(f"Error comparing file paths: {e}")
|
42
43
|
try:
|
43
44
|
code = file_path.read_text()
|
44
45
|
code = self.remove_docstrings(code)
|
45
46
|
code = self.remove_line_comments(code)
|
46
47
|
code = self.remove_extra_whitespace(code)
|
47
48
|
code = self.reformat_code(code)
|
48
|
-
file_path.write_text(code)
|
49
|
-
print(f"Cleaned: {file_path}")
|
49
|
+
file_path.write_text(code) # type: ignore
|
50
|
+
self.console.print(f"Cleaned: {file_path}")
|
50
51
|
except Exception as e:
|
51
|
-
print(f"Error cleaning {file_path}: {e}")
|
52
|
+
self.console.print(f"Error cleaning {file_path}: {e}")
|
52
53
|
|
53
54
|
def remove_line_comments(self, code: str) -> str:
|
54
55
|
new_lines = []
|
@@ -59,38 +60,98 @@ class CodeCleaner(BaseModel, arbitrary_types_allowed=True):
|
|
59
60
|
idx = line.find("#")
|
60
61
|
code_part = line[:idx].rstrip()
|
61
62
|
comment_part = line[idx:]
|
62
|
-
if
|
63
|
+
if (
|
64
|
+
"type: ignore" in comment_part
|
65
|
+
or "noqa" in comment_part
|
66
|
+
or "nosec" in comment_part
|
67
|
+
):
|
63
68
|
new_lines.append(line)
|
64
69
|
else:
|
65
70
|
if code_part:
|
66
71
|
new_lines.append(code_part)
|
67
72
|
return "\n".join(new_lines)
|
68
73
|
|
74
|
+
def _is_triple_quoted(self, token_string: str) -> bool:
|
75
|
+
triple_quote_patterns = [
|
76
|
+
('"""', '"""'),
|
77
|
+
("'''", "'''"),
|
78
|
+
('r"""', '"""'),
|
79
|
+
("r'''", "'''"),
|
80
|
+
]
|
81
|
+
return any(
|
82
|
+
token_string.startswith(start) and token_string.endswith(end)
|
83
|
+
for start, end in triple_quote_patterns
|
84
|
+
)
|
85
|
+
|
86
|
+
def _is_module_docstring(
|
87
|
+
self, tokens: list[tokenize.TokenInfo], i: int, indent_level: int
|
88
|
+
) -> bool:
|
89
|
+
if i <= 0 or indent_level != 0:
|
90
|
+
return False
|
91
|
+
preceding_tokens = tokens[:i]
|
92
|
+
return not preceding_tokens
|
93
|
+
|
94
|
+
def _is_function_or_class_docstring(
|
95
|
+
self,
|
96
|
+
tokens: list[tokenize.TokenInfo],
|
97
|
+
i: int,
|
98
|
+
last_token_type: t.Any,
|
99
|
+
last_token_string: str,
|
100
|
+
) -> bool:
|
101
|
+
if last_token_type != tokenize.OP or last_token_string != ":": # nosec B105
|
102
|
+
return False
|
103
|
+
for prev_idx in range(i - 1, max(0, i - 20), -1):
|
104
|
+
prev_token = tokens[prev_idx]
|
105
|
+
if prev_token[1] in ("def", "class") and prev_token[0] == tokenize.NAME:
|
106
|
+
return True
|
107
|
+
elif prev_token[0] == tokenize.DEDENT:
|
108
|
+
break
|
109
|
+
return False
|
110
|
+
|
111
|
+
def _is_variable_docstring(
|
112
|
+
self, tokens: list[tokenize.TokenInfo], i: int, indent_level: int
|
113
|
+
) -> bool:
|
114
|
+
if indent_level <= 0:
|
115
|
+
return False
|
116
|
+
for prev_idx in range(i - 1, max(0, i - 10), -1):
|
117
|
+
if tokens[prev_idx][0]:
|
118
|
+
return True
|
119
|
+
return False
|
120
|
+
|
69
121
|
def remove_docstrings(self, source: str) -> str:
|
70
122
|
try:
|
71
123
|
io_obj = io.StringIO(source)
|
72
|
-
output_tokens = []
|
73
|
-
first_token_stack = [True]
|
74
124
|
tokens = list(tokenize.generate_tokens(io_obj.readline))
|
75
|
-
|
76
|
-
|
125
|
+
result_tokens = []
|
126
|
+
indent_level = 0
|
127
|
+
last_non_ws_token_type = None
|
128
|
+
last_non_ws_token_string = "" # nosec B105
|
129
|
+
for i, token in enumerate(tokens):
|
130
|
+
token_type, token_string, _, _, _ = token
|
77
131
|
if token_type == tokenize.INDENT:
|
78
|
-
|
132
|
+
indent_level += 1
|
79
133
|
elif token_type == tokenize.DEDENT:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
134
|
+
indent_level -= 1
|
135
|
+
if token_type == STRING and self._is_triple_quoted(token_string):
|
136
|
+
is_docstring = (
|
137
|
+
self._is_module_docstring(tokens, i, indent_level)
|
138
|
+
or self._is_function_or_class_docstring(
|
139
|
+
tokens, i, last_non_ws_token_type, last_non_ws_token_string
|
140
|
+
)
|
141
|
+
or self._is_variable_docstring(tokens, i, indent_level)
|
142
|
+
)
|
143
|
+
if is_docstring:
|
144
|
+
continue
|
145
|
+
if token_type not in (
|
146
|
+
tokenize.NL,
|
147
|
+
tokenize.NEWLINE,
|
148
|
+
tokenize.INDENT,
|
149
|
+
tokenize.DEDENT,
|
150
|
+
):
|
151
|
+
last_non_ws_token_type = token_type
|
152
|
+
last_non_ws_token_string = token_string
|
153
|
+
result_tokens.append(token)
|
154
|
+
return tokenize.untokenize(result_tokens)
|
94
155
|
except Exception as e:
|
95
156
|
self.console.print(f"Error removing docstrings: {e}")
|
96
157
|
return source
|
@@ -105,7 +166,7 @@ class CodeCleaner(BaseModel, arbitrary_types_allowed=True):
|
|
105
166
|
cleaned_lines.append(line)
|
106
167
|
return "\n".join(cleaned_lines)
|
107
168
|
|
108
|
-
def reformat_code(self, code: str) -> str:
|
169
|
+
def reformat_code(self, code: str) -> str | None:
|
109
170
|
try:
|
110
171
|
import tempfile
|
111
172
|
|
@@ -124,21 +185,22 @@ class CodeCleaner(BaseModel, arbitrary_types_allowed=True):
|
|
124
185
|
if result.returncode == 0:
|
125
186
|
formatted_code = temp_path.read_text()
|
126
187
|
else:
|
127
|
-
print(f"Ruff formatting failed: {result.stderr}")
|
188
|
+
self.console.print(f"Ruff formatting failed: {result.stderr}")
|
128
189
|
formatted_code = code
|
129
190
|
except Exception as e:
|
130
|
-
print(f"Error running Ruff: {e}")
|
191
|
+
self.console.print(f"Error running Ruff: {e}")
|
131
192
|
formatted_code = code
|
132
193
|
finally:
|
133
194
|
with suppress(FileNotFoundError):
|
134
195
|
temp_path.unlink()
|
135
196
|
return formatted_code
|
136
197
|
except Exception as e:
|
137
|
-
print(f"Error during reformatting: {e}")
|
198
|
+
self.console.print(f"Error during reformatting: {e}")
|
138
199
|
return code
|
139
200
|
|
140
201
|
|
141
|
-
|
202
|
+
@dataclass
|
203
|
+
class ConfigManager:
|
142
204
|
our_path: Path
|
143
205
|
pkg_path: Path
|
144
206
|
pkg_name: str
|
@@ -262,14 +324,15 @@ class ConfigManager(BaseModel, arbitrary_types_allowed=True):
|
|
262
324
|
return execute(cmd, **kwargs)
|
263
325
|
|
264
326
|
|
265
|
-
|
327
|
+
@dataclass
|
328
|
+
class ProjectManager:
|
266
329
|
our_path: Path
|
267
330
|
pkg_path: Path
|
268
|
-
pkg_dir: Path | None = None
|
269
|
-
pkg_name: str = "crackerjack"
|
270
331
|
console: Console
|
271
332
|
code_cleaner: CodeCleaner
|
272
333
|
config_manager: ConfigManager
|
334
|
+
pkg_dir: Path | None = None
|
335
|
+
pkg_name: str = "crackerjack"
|
273
336
|
dry_run: bool = False
|
274
337
|
|
275
338
|
def run_interactive(self, hook: str) -> None:
|
@@ -321,39 +384,42 @@ class ProjectManager(BaseModel, arbitrary_types_allowed=True):
|
|
321
384
|
return execute(cmd, **kwargs)
|
322
385
|
|
323
386
|
|
324
|
-
|
325
|
-
|
326
|
-
|
387
|
+
@dataclass
|
388
|
+
class Crackerjack:
|
389
|
+
our_path: Path = field(default_factory=lambda: Path(__file__).parent)
|
390
|
+
pkg_path: Path = field(default_factory=lambda: Path(Path.cwd()))
|
327
391
|
pkg_dir: Path | None = None
|
328
392
|
pkg_name: str = "crackerjack"
|
329
393
|
python_version: str = default_python_version
|
330
|
-
console: Console = Console(force_terminal=True)
|
394
|
+
console: Console = field(default_factory=lambda: Console(force_terminal=True))
|
331
395
|
dry_run: bool = False
|
332
396
|
code_cleaner: CodeCleaner | None = None
|
333
397
|
config_manager: ConfigManager | None = None
|
334
398
|
project_manager: ProjectManager | None = None
|
335
399
|
|
336
|
-
def
|
337
|
-
|
338
|
-
|
339
|
-
self.config_manager
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
400
|
+
def __post_init__(self) -> None:
|
401
|
+
if self.code_cleaner is None:
|
402
|
+
self.code_cleaner = CodeCleaner(console=self.console)
|
403
|
+
if self.config_manager is None:
|
404
|
+
self.config_manager = ConfigManager(
|
405
|
+
our_path=self.our_path,
|
406
|
+
pkg_path=self.pkg_path,
|
407
|
+
pkg_name=self.pkg_name,
|
408
|
+
console=self.console,
|
409
|
+
python_version=self.python_version,
|
410
|
+
dry_run=self.dry_run,
|
411
|
+
)
|
412
|
+
if self.project_manager is None:
|
413
|
+
self.project_manager = ProjectManager(
|
414
|
+
our_path=self.our_path,
|
415
|
+
pkg_path=self.pkg_path,
|
416
|
+
pkg_dir=self.pkg_dir,
|
417
|
+
pkg_name=self.pkg_name,
|
418
|
+
console=self.console,
|
419
|
+
code_cleaner=self.code_cleaner,
|
420
|
+
config_manager=self.config_manager,
|
421
|
+
dry_run=self.dry_run,
|
422
|
+
)
|
357
423
|
|
358
424
|
def _setup_package(self) -> None:
|
359
425
|
self.pkg_name = self.pkg_path.stem.lower().replace("-", "_")
|
crackerjack/pyproject.toml
CHANGED
@@ -2,9 +2,10 @@
|
|
2
2
|
addopts = "--cov=crackerjack"
|
3
3
|
asyncio_default_fixture_loop_scope = "function"
|
4
4
|
python_files = ["test_*.py", "*_test.py"]
|
5
|
-
python_classes = "Test*"
|
6
|
-
python_functions = "test_*"
|
7
5
|
asyncio_mode = "auto"
|
6
|
+
testpaths = ["tests", "crackerjack"]
|
7
|
+
python_classes = ["Test*"]
|
8
|
+
python_functions = ["test_*"]
|
8
9
|
|
9
10
|
[tool.coverage.run]
|
10
11
|
branch = true
|
@@ -14,6 +15,7 @@ omit = [
|
|
14
15
|
"*/site-packages/*",
|
15
16
|
"*/__pycache__/*",
|
16
17
|
"*/__init__.py",
|
18
|
+
"*/_version.py", "*/conftest.py", "*/test_*.py", "*/_test.py"
|
17
19
|
]
|
18
20
|
|
19
21
|
[tool.coverage.report]
|
@@ -147,7 +149,7 @@ pythonPlatform = "Darwin"
|
|
147
149
|
|
148
150
|
[project]
|
149
151
|
name = "crackerjack"
|
150
|
-
version = "0.14.
|
152
|
+
version = "0.14.5"
|
151
153
|
description = "Default template for PDM package"
|
152
154
|
requires-python = ">=3.13"
|
153
155
|
readme = "README.md"
|
@@ -174,12 +176,12 @@ classifiers = [
|
|
174
176
|
]
|
175
177
|
dependencies = [
|
176
178
|
"autotyping>=24.9.0",
|
177
|
-
"pre-commit>=4.
|
179
|
+
"pre-commit>=4.2.0",
|
178
180
|
"pytest>=8.3.5",
|
179
181
|
"pydantic>=2.10.6",
|
180
182
|
"pdm-bump>=0.9.10",
|
181
183
|
"pdm>=2.22.4",
|
182
|
-
"uv>=0.6.
|
184
|
+
"uv>=0.6.9",
|
183
185
|
"pytest-cov>=6.0.0",
|
184
186
|
"pytest-mock>=3.14.0",
|
185
187
|
"tomli-w>=1.2.0",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: crackerjack
|
3
|
-
Version: 0.14.
|
3
|
+
Version: 0.14.6
|
4
4
|
Summary: Default template for PDM package
|
5
5
|
Keywords: black,ruff,mypy,creosote,refurb
|
6
6
|
Author-Email: lesleslie <les@wedgwoodwebworks.com>
|
@@ -23,12 +23,12 @@ Project-URL: documentation, https://github.com/lesleslie/crackerjack
|
|
23
23
|
Project-URL: repository, https://github.com/lesleslie/crackerjack
|
24
24
|
Requires-Python: >=3.13
|
25
25
|
Requires-Dist: autotyping>=24.9.0
|
26
|
-
Requires-Dist: pre-commit>=4.
|
26
|
+
Requires-Dist: pre-commit>=4.2.0
|
27
27
|
Requires-Dist: pytest>=8.3.5
|
28
28
|
Requires-Dist: pydantic>=2.10.6
|
29
29
|
Requires-Dist: pdm-bump>=0.9.10
|
30
30
|
Requires-Dist: pdm>=2.22.4
|
31
|
-
Requires-Dist: uv>=0.6.
|
31
|
+
Requires-Dist: uv>=0.6.9
|
32
32
|
Requires-Dist: pytest-cov>=6.0.0
|
33
33
|
Requires-Dist: pytest-mock>=3.14.0
|
34
34
|
Requires-Dist: tomli-w>=1.2.0
|
@@ -1,12 +1,12 @@
|
|
1
|
-
crackerjack-0.14.
|
2
|
-
crackerjack-0.14.
|
3
|
-
crackerjack-0.14.
|
4
|
-
crackerjack-0.14.
|
1
|
+
crackerjack-0.14.6.dist-info/METADATA,sha256=bij1KNnKB8-YQUvZKjue_kQvCQdbW9-oCu_o7h03PlI,11033
|
2
|
+
crackerjack-0.14.6.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
3
|
+
crackerjack-0.14.6.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
|
4
|
+
crackerjack-0.14.6.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
|
5
5
|
crackerjack/.coverage,sha256=dLzPzp72qZEXohNfxnOAlRwvM9dqF06-HoFqfvXZd1U,53248
|
6
6
|
crackerjack/.gitignore,sha256=l8ErBAypC3rI6N9lhc7ZMdOw87t0Tz69ZW5C6uj15Wg,214
|
7
7
|
crackerjack/.libcst.codemod.yaml,sha256=a8DlErRAIPV1nE6QlyXPAzTOgkB24_spl2E9hphuf5s,772
|
8
8
|
crackerjack/.pdm.toml,sha256=dZe44HRcuxxCFESGG8SZIjmc-cGzSoyK3Hs6t4NYA8w,23
|
9
|
-
crackerjack/.pre-commit-config.yaml,sha256=
|
9
|
+
crackerjack/.pre-commit-config.yaml,sha256=rb_3cBRHFSzWYC1OW8mLkFC7A8Retb0zdyeIM5FUQ1I,2267
|
10
10
|
crackerjack/.pytest_cache/.gitignore,sha256=Ptcxtl0GFQwTji2tsL4Gl1UIiKa0frjEXsya26i46b0,37
|
11
11
|
crackerjack/.pytest_cache/CACHEDIR.TAG,sha256=N9yI75oKvt2-gQU6bdj9-xOvthMEXqHrSlyBWnSjveQ,191
|
12
12
|
crackerjack/.pytest_cache/README.md,sha256=c_1vzN2ALEGaay2YPWwxc7fal1WKxLWJ7ewt_kQ9ua0,302
|
@@ -19,6 +19,7 @@ crackerjack/.ruff_cache/0.1.4/10355199064880463147,sha256=kmqNg5WySQYPeAqa5elfaV
|
|
19
19
|
crackerjack/.ruff_cache/0.1.6/15140459877605758699,sha256=oQy5boAXeskdm5M0Abh_nyBtitWj5N5wtx_4gsDgu7c,248
|
20
20
|
crackerjack/.ruff_cache/0.1.7/1790508110482614856,sha256=De7Puq32XF0925xrGehWSKX6cw5Wi2bpt1cnqh__f54,248
|
21
21
|
crackerjack/.ruff_cache/0.1.9/17041001205004563469,sha256=tKP_k8HaHhQJyrHbDfJ93kM7vahjrU8cKQ1f_-OUzZY,248
|
22
|
+
crackerjack/.ruff_cache/0.11.2/4070660268492669020,sha256=kE8I-PoRXnXRfzmPQW3GO_fgkN4H43CtWvW_L0PLQHc,224
|
22
23
|
crackerjack/.ruff_cache/0.2.0/10047773857155985907,sha256=j9LNa_RQ4Plor7go1uTYgz17cEENKvZQ-dP6b9MX0ik,248
|
23
24
|
crackerjack/.ruff_cache/0.2.1/8522267973936635051,sha256=u_aPBMibtAp_iYvLwR88GMAECMcIgHezxMyuapmU2P4,248
|
24
25
|
crackerjack/.ruff_cache/0.2.2/18053836298936336950,sha256=Xb_ebP0pVuUfSqPEZKlhQ70so_vqkEfMYpuHQ06iR5U,248
|
@@ -48,6 +49,6 @@ crackerjack/.ruff_cache/0.9.9/8843823720003377982,sha256=e4ymkXfQsUg5e_mtO34xTsa
|
|
48
49
|
crackerjack/.ruff_cache/CACHEDIR.TAG,sha256=WVMVbX4MVkpCclExbq8m-IcOZIOuIZf5FrYw5Pk-Ma4,43
|
49
50
|
crackerjack/__init__.py,sha256=XTWW_XQkWR6dSydFSLg-T--eY3TPKUp4jUwZP11kgwY,142
|
50
51
|
crackerjack/__main__.py,sha256=7SHrcRFYhMaSV0S-EG8q2w8udURwdvIsS7vi9AW4naU,3784
|
51
|
-
crackerjack/crackerjack.py,sha256=
|
52
|
-
crackerjack/pyproject.toml,sha256=
|
53
|
-
crackerjack-0.14.
|
52
|
+
crackerjack/crackerjack.py,sha256=TupEH0hqRaB5hp4ZBMyGzdw4UjF_KT00wYhyo4o0khU,21338
|
53
|
+
crackerjack/pyproject.toml,sha256=0YJzFZP2CxyWMc4d4eF85zD8Y2N5hmb04xf9p0VFATY,4088
|
54
|
+
crackerjack-0.14.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|