crackerjack 0.14.9__py3-none-any.whl → 0.15.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.
crackerjack/.gitignore CHANGED
@@ -13,5 +13,4 @@
13
13
  /*.pyc
14
14
  /.crackerjack.yaml
15
15
  /scratch/
16
-
17
- .qodo
16
+ /.zencoder/
@@ -26,7 +26,7 @@ repos:
26
26
  hooks:
27
27
  - id: vulture
28
28
  - repo: https://github.com/fredrikaverpil/creosote
29
- rev: v4.0.1
29
+ rev: v4.0.2
30
30
  hooks:
31
31
  - id: creosote
32
32
  - repo: https://github.com/ikamensh/flynt/
crackerjack/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
- from typing import Sequence
1
+ import typing as t
2
2
 
3
- from .crackerjack import Crackerjack, crackerjack_it
3
+ from .crackerjack import Crackerjack, create_crackerjack_runner
4
4
 
5
- __all__: Sequence[str] = ["crackerjack_it", "Crackerjack"]
5
+ __all__: t.Sequence[str] = ["create_crackerjack_runner", "Crackerjack"]
crackerjack/__main__.py CHANGED
@@ -1,10 +1,9 @@
1
- import typing as t
2
1
  from enum import Enum
3
2
 
4
3
  import typer
5
4
  from pydantic import BaseModel, field_validator
6
5
  from rich.console import Console
7
- from crackerjack import crackerjack_it
6
+ from crackerjack import create_crackerjack_runner
8
7
 
9
8
  console = Console(force_terminal=True)
10
9
  app = typer.Typer(
@@ -26,17 +25,17 @@ class Options(BaseModel):
26
25
  interactive: bool = False
27
26
  doc: bool = False
28
27
  no_config_updates: bool = False
29
- publish: t.Optional[BumpOption] = None
30
- bump: t.Optional[BumpOption] = None
28
+ publish: BumpOption | None = None
29
+ bump: BumpOption | None = None
31
30
  verbose: bool = False
32
31
  update_precommit: bool = False
33
32
  clean: bool = False
34
33
  test: bool = False
35
- all: t.Optional[BumpOption] = None
34
+ all: BumpOption | None = None
36
35
 
37
36
  @classmethod
38
37
  @field_validator("publish", "bump", mode="before")
39
- def validate_bump_options(cls, value: t.Optional[str]) -> t.Optional[BumpOption]:
38
+ def validate_bump_options(cls, value: str | None) -> BumpOption | None:
40
39
  if value is None:
41
40
  return None
42
41
  try:
@@ -92,10 +91,6 @@ cli_options = {
92
91
  }
93
92
 
94
93
 
95
- def create_options(**kwargs: t.Any) -> Options:
96
- return Options(**kwargs)
97
-
98
-
99
94
  @app.command()
100
95
  def main(
101
96
  commit: bool = cli_options["commit"],
@@ -104,13 +99,13 @@ def main(
104
99
  no_config_updates: bool = cli_options["no_config_updates"],
105
100
  update_precommit: bool = cli_options["update_precommit"],
106
101
  verbose: bool = cli_options["verbose"],
107
- publish: t.Optional[BumpOption] = cli_options["publish"],
108
- all: t.Optional[BumpOption] = cli_options["all"],
109
- bump: t.Optional[BumpOption] = cli_options["bump"],
102
+ publish: BumpOption | None = cli_options["publish"],
103
+ all: BumpOption | None = cli_options["all"],
104
+ bump: BumpOption | None = cli_options["bump"],
110
105
  clean: bool = cli_options["clean"],
111
106
  test: bool = cli_options["test"],
112
107
  ) -> None:
113
- options = create_options(
108
+ options = Options(
114
109
  commit=commit,
115
110
  interactive=interactive,
116
111
  doc=doc,
@@ -123,7 +118,9 @@ def main(
123
118
  test=test,
124
119
  all=all,
125
120
  )
126
- crackerjack_it(options)
121
+
122
+ runner = create_crackerjack_runner(console=console)
123
+ runner.process(options)
127
124
 
128
125
 
129
126
  if __name__ == "__main__":
@@ -20,6 +20,28 @@ interactive_hooks = ("refurb", "bandit", "pyright")
20
20
  default_python_version = "3.13"
21
21
 
22
22
 
23
+ @t.runtime_checkable
24
+ class CommandRunner(t.Protocol):
25
+ def execute_command(
26
+ self, cmd: list[str], **kwargs: t.Any
27
+ ) -> subprocess.CompletedProcess[str]: ...
28
+
29
+
30
+ @t.runtime_checkable
31
+ class OptionsProtocol(t.Protocol):
32
+ commit: bool
33
+ interactive: bool
34
+ doc: bool
35
+ no_config_updates: bool
36
+ verbose: bool
37
+ update_precommit: bool
38
+ clean: bool
39
+ test: bool
40
+ publish: t.Any | None
41
+ bump: t.Any | None
42
+ all: t.Any | None
43
+
44
+
23
45
  @dataclass
24
46
  class CodeCleaner:
25
47
  console: Console
@@ -430,7 +452,7 @@ class Crackerjack:
430
452
  self.project_manager.pkg_name = self.pkg_name
431
453
  self.project_manager.pkg_dir = self.pkg_dir
432
454
 
433
- def _update_project(self, options: t.Any) -> None:
455
+ def _update_project(self, options: OptionsProtocol) -> None:
434
456
  if not options.no_config_updates:
435
457
  self.project_manager.update_pkg_configs()
436
458
  result: CompletedProcess[str] = self.execute_command(
@@ -443,16 +465,16 @@ class Crackerjack:
443
465
  "\n\n❌ PDM installation failed. Is PDM is installed? Run `pipx install pdm` and try again.\n\n"
444
466
  )
445
467
 
446
- def _update_precommit(self, options: t.Any) -> None:
468
+ def _update_precommit(self, options: OptionsProtocol) -> None:
447
469
  if self.pkg_path.stem == "crackerjack" and options.update_precommit:
448
470
  self.execute_command(["pre-commit", "autoupdate"])
449
471
 
450
- def _run_interactive_hooks(self, options: t.Any) -> None:
472
+ def _run_interactive_hooks(self, options: OptionsProtocol) -> None:
451
473
  if options.interactive:
452
474
  for hook in interactive_hooks:
453
475
  self.project_manager.run_interactive(hook)
454
476
 
455
- def _clean_project(self, options: t.Any) -> None:
477
+ def _clean_project(self, options: OptionsProtocol) -> None:
456
478
  if options.clean:
457
479
  if self.pkg_dir:
458
480
  self.code_cleaner.clean_files(self.pkg_dir)
@@ -461,7 +483,7 @@ class Crackerjack:
461
483
  self.console.print("\nCleaning tests directory...\n")
462
484
  self.code_cleaner.clean_files(tests_dir)
463
485
 
464
- def _run_tests(self, options: t.Any) -> None:
486
+ def _run_tests(self, options: OptionsProtocol) -> None:
465
487
  if options.test:
466
488
  self.console.print("\n\nRunning tests...\n")
467
489
  test = ["pytest"]
@@ -477,13 +499,13 @@ class Crackerjack:
477
499
  raise SystemExit(1)
478
500
  self.console.print("\n\n✅ Tests passed successfully!\n")
479
501
 
480
- def _bump_version(self, options: t.Any) -> None:
502
+ def _bump_version(self, options: OptionsProtocol) -> None:
481
503
  for option in (options.publish, options.bump):
482
504
  if option:
483
505
  self.execute_command(["pdm", "bump", option])
484
506
  break
485
507
 
486
- def _publish_project(self, options: t.Any) -> None:
508
+ def _publish_project(self, options: OptionsProtocol) -> None:
487
509
  if options.publish:
488
510
  if platform.system() == "Darwin":
489
511
  authorize = self.execute_command(
@@ -504,7 +526,7 @@ class Crackerjack:
504
526
  raise SystemExit(1)
505
527
  self.execute_command(["pdm", "publish", "--no-build"])
506
528
 
507
- def _commit_and_push(self, options: t.Any) -> None:
529
+ def _commit_and_push(self, options: OptionsProtocol) -> None:
508
530
  if options.commit:
509
531
  commit_msg = input("\nCommit message: ")
510
532
  self.execute_command(
@@ -520,7 +542,7 @@ class Crackerjack:
520
542
  return CompletedProcess(cmd, 0, "", "")
521
543
  return execute(cmd, **kwargs)
522
544
 
523
- def process(self, options: t.Any) -> None:
545
+ def process(self, options: OptionsProtocol) -> None:
524
546
  if options.all:
525
547
  options.clean = True
526
548
  options.test = True
@@ -536,7 +558,20 @@ class Crackerjack:
536
558
  self._bump_version(options)
537
559
  self._publish_project(options)
538
560
  self._commit_and_push(options)
539
- self.console.print("\nCrackerjack complete!\n")
540
-
541
-
542
- crackerjack_it = Crackerjack().process
561
+ self.console.print("\n🍺 Crackerjack complete!\n")
562
+
563
+
564
+ def create_crackerjack_runner(
565
+ console: Console | None = None,
566
+ our_path: Path | None = None,
567
+ pkg_path: Path | None = None,
568
+ python_version: str = default_python_version,
569
+ dry_run: bool = False,
570
+ ) -> Crackerjack:
571
+ return Crackerjack(
572
+ console=console or Console(force_terminal=True),
573
+ our_path=our_path or Path(__file__).parent,
574
+ pkg_path=pkg_path or Path.cwd(),
575
+ python_version=python_version,
576
+ dry_run=dry_run,
577
+ )
@@ -149,7 +149,7 @@ pythonPlatform = "Darwin"
149
149
 
150
150
  [project]
151
151
  name = "crackerjack"
152
- version = "0.14.8"
152
+ version = "0.15.0"
153
153
  description = "Default template for PDM package"
154
154
  requires-python = ">=3.13"
155
155
  readme = "README.md"
@@ -178,8 +178,8 @@ dependencies = [
178
178
  "autotyping>=24.9.0",
179
179
  "pre-commit>=4.2.0",
180
180
  "pytest>=8.3.5",
181
- "pydantic>=2.10.6",
182
- "pdm-bump>=0.9.10",
181
+ "pydantic>=2.11.1",
182
+ "pdm-bump>=0.9.11.post2",
183
183
  "pdm>=2.22.4",
184
184
  "uv>=0.6.10",
185
185
  "pytest-cov>=6.0.0",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crackerjack
3
- Version: 0.14.9
3
+ Version: 0.15.1
4
4
  Summary: Default template for PDM package
5
5
  Keywords: black,ruff,mypy,creosote,refurb
6
6
  Author-Email: lesleslie <les@wedgwoodwebworks.com>
@@ -25,8 +25,8 @@ Requires-Python: >=3.13
25
25
  Requires-Dist: autotyping>=24.9.0
26
26
  Requires-Dist: pre-commit>=4.2.0
27
27
  Requires-Dist: pytest>=8.3.5
28
- Requires-Dist: pydantic>=2.10.6
29
- Requires-Dist: pdm-bump>=0.9.10
28
+ Requires-Dist: pydantic>=2.11.1
29
+ Requires-Dist: pdm-bump>=0.9.11.post2
30
30
  Requires-Dist: pdm>=2.22.4
31
31
  Requires-Dist: uv>=0.6.10
32
32
  Requires-Dist: pytest-cov>=6.0.0
@@ -125,15 +125,17 @@ Crackerjack automatically installs and manages these pre-commit hooks:
125
125
  Crackerjack projects adhere to these guidelines:
126
126
 
127
127
  - **Static Typing:** Use type hints consistently throughout your code.
128
+ - **Modern Type Hints:** Use the pipe operator (`|`) for union types (e.g., `Path | None` instead of `Optional[Path]`).
128
129
  - **Explicit Naming:** Choose clear, descriptive names for classes, functions, variables, and other identifiers.
129
130
  - **Markdown for Documentation:** Use Markdown (`.md`) for all documentation, READMEs, etc.
130
131
  - **Pathlib:** Use `pathlib.Path` for handling file and directory paths instead of `os.path`.
131
- - **Consistent Imports:** Use `import typing as t` for type hinting.
132
+ - **Consistent Imports:** Use `import typing as t` for type hinting and prefix all typing references with `t.`.
133
+ - **Protocol-Based Design:** Use `t.Protocol` for interface definitions instead of abstract base classes.
132
134
  - **Constants and Config:** Do not use all-caps for constants or configuration settings.
133
135
  - **Path Parameters:** Functions that handle file operations should accept `pathlib.Path` objects as parameters.
134
136
  - **Dependency Management:** Use PDM for dependency management, package building, and publishing.
135
137
  - **Testing:** Use pytest as your testing framework.
136
- - **Python Version:** Crackerjack projects support the latest Python versions.
138
+ - **Python Version:** Crackerjack projects target Python 3.13+ and use the latest language features.
137
139
  - **Clear Code:** Avoid overly complex code.
138
140
  - **Modular:** Functions should do one thing well.
139
141
 
@@ -155,10 +157,48 @@ Crackerjack projects adhere to these guidelines:
155
157
 
156
158
  ## Usage
157
159
 
160
+ ### Command Line
161
+
158
162
  Run Crackerjack from the root of your Python project using:
159
163
 
160
164
  python -m crackerjack
161
165
 
166
+ ### Programmatic API
167
+
168
+ You can also use Crackerjack programmatically in your Python code:
169
+
170
+ ```python
171
+ import typing as t
172
+ from pathlib import Path
173
+ from rich.console import Console
174
+ from crackerjack import create_crackerjack_runner
175
+
176
+ # Create a custom options object
177
+ class MyOptions:
178
+ def __init__(self):
179
+ self.commit = False
180
+ self.interactive = True
181
+ self.doc = False
182
+ self.no_config_updates = False
183
+ self.verbose = True
184
+ self.update_precommit = False
185
+ self.clean = True
186
+ self.test = True
187
+ self.publish = None
188
+ self.bump = "micro"
189
+ self.all = None
190
+
191
+ # Create a Crackerjack runner with custom settings
192
+ runner = create_crackerjack_runner(
193
+ console=Console(force_terminal=True),
194
+ pkg_path=Path.cwd(),
195
+ python_version="3.13"
196
+ )
197
+
198
+ # Run Crackerjack with your options
199
+ runner.process(MyOptions())
200
+ ```
201
+
162
202
 
163
203
  ### Command-Line Options
164
204
 
@@ -244,6 +284,17 @@ This ensures your code meets all quality standards before submission.
244
284
 
245
285
  This project is licensed under the terms of the BSD 3-Clause license.
246
286
 
287
+ ## Architecture
288
+
289
+ Crackerjack is designed with modern Python principles in mind:
290
+
291
+ - **Factory Pattern:** Uses a factory function (`create_crackerjack_runner`) to create instances with proper dependency injection
292
+ - **Protocol-Based Design:** Defines clear interfaces using `t.Protocol` for better flexibility and testability
293
+ - **Dependency Injection:** Components can be easily replaced with custom implementations
294
+ - **Separation of Concerns:** CLI interface is separate from core logic
295
+ - **Type Safety:** Comprehensive type hints throughout the codebase
296
+ - **Testability:** Designed to be easily testable with mock objects
297
+
247
298
  ## Acknowledgments
248
299
 
249
300
  - **PDM:** For excellent dependency and virtual environment management.
@@ -251,14 +302,14 @@ This project is licensed under the terms of the BSD 3-Clause license.
251
302
  - **pre-commit:** For the robust hook management system.
252
303
  - **pytest:** For the flexible and powerful testing framework.
253
304
  - **uv:** For greatly improving PDM speeds.
254
- - **bandit:** For finding security vulnerabilities.
255
- - **vulture:** for dead code detection.
256
- - **creosote:** For unused dependency detection.
257
- - **flynt:** For f-string conversion.
258
- - **codespell:** For spelling correction.
259
- - **autotyping:** For automatically adding type hints.
260
- - **refurb:** For code improvement suggestions.
261
- - **pyright:** For static type checking.
262
- - **Typer:** For the creation of the CLI.
305
+ - **bandit:** For finding security vulnerabilities.
306
+ - **vulture:** For dead code detection.
307
+ - **creosote:** For unused dependency detection.
308
+ - **flynt:** For f-string conversion.
309
+ - **codespell:** For spelling correction.
310
+ - **autotyping:** For automatically adding type hints.
311
+ - **refurb:** For code improvement suggestions.
312
+ - **pyright:** For static type checking.
313
+ - **Typer:** For the creation of the CLI.
263
314
 
264
315
  ---
@@ -1,12 +1,12 @@
1
- crackerjack-0.14.9.dist-info/METADATA,sha256=51Y-eUXW4uIivey-a-xrVEuQmexAGuYNnqP5wObGGwU,11034
2
- crackerjack-0.14.9.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
- crackerjack-0.14.9.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- crackerjack-0.14.9.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
1
+ crackerjack-0.15.1.dist-info/METADATA,sha256=Bk1H0SPqglhXFatKKrWHoSSlYdOvAiYAECdT9Glfkyo,12869
2
+ crackerjack-0.15.1.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
+ crackerjack-0.15.1.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ crackerjack-0.15.1.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
5
5
  crackerjack/.coverage,sha256=dLzPzp72qZEXohNfxnOAlRwvM9dqF06-HoFqfvXZd1U,53248
6
- crackerjack/.gitignore,sha256=l8ErBAypC3rI6N9lhc7ZMdOw87t0Tz69ZW5C6uj15Wg,214
6
+ crackerjack/.gitignore,sha256=ts3GBu94chiwTyOCNCMHau9M8XGrd1yajyHPAMo_Z84,219
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=EV0rFTyN2znrzS6dc-QUg1uHKMrV98z2tMjRUpyV_P0,2267
9
+ crackerjack/.pre-commit-config.yaml,sha256=ay4tWUdPjKC0aQVfU-FxnFHOXZU5GZ4_W74yVuczpHg,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,7 +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=Op16lNybLTJgeVZVIeTGnKIEeiGrzBwOwh0Nh1pN_Ss,224
22
+ crackerjack/.ruff_cache/0.11.2/4070660268492669020,sha256=E5tD_n3l9VlB-dtvBPyKF0CKRdAnrs2ofL8PIaznUo8,224
23
23
  crackerjack/.ruff_cache/0.2.0/10047773857155985907,sha256=j9LNa_RQ4Plor7go1uTYgz17cEENKvZQ-dP6b9MX0ik,248
24
24
  crackerjack/.ruff_cache/0.2.1/8522267973936635051,sha256=u_aPBMibtAp_iYvLwR88GMAECMcIgHezxMyuapmU2P4,248
25
25
  crackerjack/.ruff_cache/0.2.2/18053836298936336950,sha256=Xb_ebP0pVuUfSqPEZKlhQ70so_vqkEfMYpuHQ06iR5U,248
@@ -47,8 +47,8 @@ crackerjack/.ruff_cache/0.9.3/13948373885254993391,sha256=kGhtIkzPUtKAgvlKs3D8j4
47
47
  crackerjack/.ruff_cache/0.9.9/12813592349865671909,sha256=tmr8_vhRD2OxsVuMfbJPdT9fDFX-d5tfC5U9jgziyho,224
48
48
  crackerjack/.ruff_cache/0.9.9/8843823720003377982,sha256=e4ymkXfQsUg5e_mtO34xTsaTvs1uA3_fI216Qq9qCAM,136
49
49
  crackerjack/.ruff_cache/CACHEDIR.TAG,sha256=WVMVbX4MVkpCclExbq8m-IcOZIOuIZf5FrYw5Pk-Ma4,43
50
- crackerjack/__init__.py,sha256=XTWW_XQkWR6dSydFSLg-T--eY3TPKUp4jUwZP11kgwY,142
51
- crackerjack/__main__.py,sha256=7SHrcRFYhMaSV0S-EG8q2w8udURwdvIsS7vi9AW4naU,3784
52
- crackerjack/crackerjack.py,sha256=xjGDSUIl0vbNA9SfsP0lzs7eWD33yk0yeXxnmvQz3Qg,21365
53
- crackerjack/pyproject.toml,sha256=5FBnczdH9wR4u9EooqzyHXQd6eK1vI1GJ5Vm3G-xh04,4089
54
- crackerjack-0.14.9.dist-info/RECORD,,
50
+ crackerjack/__init__.py,sha256=r9SuEjHUrW99hFWifRk4ofmYPSgf9rblcnzqhdV5bP0,157
51
+ crackerjack/__main__.py,sha256=iwoUyUB9j3e5lC5ViNAqW00eeoIx0xljNmWC04AiPaw,3707
52
+ crackerjack/crackerjack.py,sha256=alZ44ZldvqTpKo2RkAA0kq9RTueFeYeq__YbRlLN1Vg,22355
53
+ crackerjack/pyproject.toml,sha256=4pf0QYHaHTHlY-PUqlId3UV4JYyaasr-xtgOVmju2uM,4095
54
+ crackerjack-0.15.1.dist-info/RECORD,,