crackerjack 0.21.7__tar.gz → 0.22.0__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.
Files changed (90) hide show
  1. {crackerjack-0.21.7 → crackerjack-0.22.0}/PKG-INFO +10 -12
  2. {crackerjack-0.21.7 → crackerjack-0.22.0}/README.md +9 -11
  3. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.pre-commit-config.yaml +1 -17
  4. crackerjack-0.22.0/crackerjack/.ruff_cache/0.12.1/5056746222905752453 +0 -0
  5. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/__init__.py +1 -0
  6. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/__main__.py +1 -4
  7. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/crackerjack.py +148 -5
  8. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/errors.py +1 -0
  9. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/interactive.py +2 -0
  10. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/pyproject.toml +1 -1
  11. {crackerjack-0.21.7 → crackerjack-0.22.0}/pyproject.toml +1 -1
  12. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/conftest.py +1 -0
  13. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_crackerjack.py +4 -0
  14. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_crackerjack_runner.py +1 -1
  15. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_errors.py +1 -0
  16. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_interactive.py +1 -0
  17. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_interactive_run.py +1 -0
  18. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_main.py +3 -19
  19. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_multiline_functions.py +1 -0
  20. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_py313_advanced.py +1 -0
  21. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_py313_features.py +1 -0
  22. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_pytest_features.py +1 -0
  23. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/test_structured_errors.py +1 -0
  24. crackerjack-0.21.7/crackerjack/.ruff_cache/0.12.1/5056746222905752453 +0 -0
  25. {crackerjack-0.21.7 → crackerjack-0.22.0}/LICENSE +0 -0
  26. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.gitignore +0 -0
  27. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.libcst.codemod.yaml +0 -0
  28. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.pdm.toml +0 -0
  29. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.pre-commit-config-ai.yaml +0 -0
  30. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.pytest_cache/.gitignore +0 -0
  31. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.pytest_cache/CACHEDIR.TAG +0 -0
  32. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.pytest_cache/README.md +0 -0
  33. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.pytest_cache/v/cache/nodeids +0 -0
  34. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.pytest_cache/v/cache/stepwise +0 -0
  35. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/.gitignore +0 -0
  36. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
  37. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
  38. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
  39. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
  40. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
  41. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
  42. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.11/18187162184424859798 +0 -0
  43. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.12/16869036553936192448 +0 -0
  44. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.12/1867267426380906393 +0 -0
  45. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.12/4240757255861806333 +0 -0
  46. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.12/4441409093023629623 +0 -0
  47. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.13/1867267426380906393 +0 -0
  48. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.13/4240757255861806333 +0 -0
  49. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
  50. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
  51. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
  52. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
  53. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
  54. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
  55. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
  56. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.12.0/5056746222905752453 +0 -0
  57. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
  58. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
  59. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
  60. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
  61. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
  62. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
  63. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
  64. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
  65. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
  66. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
  67. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
  68. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
  69. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
  70. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
  71. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
  72. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
  73. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
  74. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
  75. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
  76. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
  77. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
  78. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
  79. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
  80. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
  81. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
  82. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
  83. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/.ruff_cache/CACHEDIR.TAG +0 -0
  84. {crackerjack-0.21.7 → crackerjack-0.22.0}/crackerjack/py313.py +0 -0
  85. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/TESTING.md +0 -0
  86. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/__init__.py +0 -0
  87. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/data/comments_sample.txt +0 -0
  88. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/data/docstrings_sample.txt +0 -0
  89. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/data/expected_comments_sample.txt +0 -0
  90. {crackerjack-0.21.7 → crackerjack-0.22.0}/tests/data/init.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crackerjack
3
- Version: 0.21.7
3
+ Version: 0.22.0
4
4
  Summary: Crackerjack: code quality toolkit
5
5
  Keywords: bandit,black,creosote,mypy,pyright,pytest,refurb,ruff
6
6
  Author-Email: lesleslie <les@wedgwoodwebworks.com>
@@ -102,7 +102,7 @@ If you're new to Crackerjack, follow these steps:
102
102
 
103
103
  Or use the interactive Rich UI:
104
104
  ```
105
- python -m crackerjack --interactive
105
+ python -m crackerjack -i
106
106
  ```
107
107
 
108
108
  ---
@@ -160,7 +160,7 @@ Crackerjack automatically installs and manages these pre-commit hooks:
160
160
  3. **Ruff:** [Ruff](https://github.com/astral-sh/ruff) for linting, code formatting, and general code style enforcement.
161
161
  4. **Vulture:** [Vulture](https://github.com/jendrikseipp/vulture) to identify dead code.
162
162
  5. **Creosote:** [Creosote](https://github.com/fredrikaverpil/creosote) to detect unused dependencies.
163
- 6. **Flynt:** [Flynt](https://github.com/ikamensh/flynt/) for converting string formatting to f-strings.
163
+ 6. **Complexipy:** [Complexipy](https://github.com/rohaquinlop/complexipy-pre-commit) for analyzing code complexity.
164
164
  7. **Codespell:** [Codespell](https://github.com/codespell-project/codespell) for correcting typos in the code.
165
165
  8. **Autotyping:** [Autotyping](https://github.com/JelleZijlstra/autotyping) for adding type hints.
166
166
  9. **Refurb:** [Refurb](https://github.com/dosisod/refurb) to suggest code improvements.
@@ -269,7 +269,7 @@ python -m crackerjack -t --benchmark-regression --benchmark-regression-threshold
269
269
 
270
270
  Or with the interactive Rich UI:
271
271
  ```
272
- python -m crackerjack --interactive
272
+ python -m crackerjack -i
273
273
  ```
274
274
 
275
275
  ## Usage
@@ -301,7 +301,6 @@ class MyOptions:
301
301
  # Configuration options
302
302
  self.no_config_updates = False # Skip updating config files
303
303
  self.update_precommit = False # Update pre-commit hooks
304
- self.doc = False # Generate documentation (not implemented yet)
305
304
 
306
305
  # Process options
307
306
  self.clean = True # Clean code (remove docstrings, comments, etc.)
@@ -347,7 +346,6 @@ runner.process(MyOptions())
347
346
  - `-i`, `--interactive`: Run pre-commit hooks interactively when possible.
348
347
  - `-n`, `--no-config-updates`: Skip updating configuration files (e.g., `pyproject.toml`).
349
348
  - `-u`, `--update-precommit`: Update pre-commit hooks to the latest versions.
350
- - `-d`, `--doc`: Generate documentation. (not yet implemented)
351
349
  - `-v`, `--verbose`: Enable verbose output.
352
350
  - `-p`, `--publish <micro|minor|major>`: Bump the project version and publish to PyPI using PDM.
353
351
  - `-b`, `--bump <micro|minor|major>`: Bump the project version without publishing.
@@ -361,7 +359,7 @@ runner.process(MyOptions())
361
359
  - `--benchmark-regression`: Fail tests if benchmarks regress beyond threshold.
362
360
  - `--benchmark-regression-threshold`: Set threshold percentage for benchmark regression (default 5.0%).
363
361
  - `-a`, `--all`: Run with `-x -t -p <micro|minor|major> -c` development options.
364
- - `--interactive`: Enable the interactive Rich UI for a more user-friendly experience with visual progress tracking and interactive prompts.
362
+ - `-i`, `--interactive`: Enable the interactive Rich UI for a more user-friendly experience with visual progress tracking and interactive prompts.
365
363
  - `--ai-agent`: Enable AI agent mode with structured output (see [AI Agent Integration](#ai-agent-integration)).
366
364
  - `--help`: Display help.
367
365
 
@@ -461,7 +459,7 @@ runner.process(MyOptions())
461
459
 
462
460
  - **Rich Interactive Mode** - Run with the interactive Rich UI:
463
461
  ```bash
464
- python -m crackerjack --interactive
462
+ python -m crackerjack -i
465
463
  ```
466
464
 
467
465
  - **AI Integration** - Run with structured output for AI tools:
@@ -500,10 +498,10 @@ Crackerjack now offers an enhanced interactive experience through its Rich UI:
500
498
  - **Error Visualization:** Errors are presented in a structured, easy-to-understand format with recovery suggestions
501
499
  - **File Selection:** Interactive file browser for operations that require selecting files
502
500
 
503
- To use the Rich UI, run Crackerjack with the `--interactive` flag:
501
+ To use the Rich UI, run Crackerjack with the `-i` flag:
504
502
 
505
503
  ```bash
506
- python -m crackerjack --interactive
504
+ python -m crackerjack -i
507
505
  ```
508
506
 
509
507
  This launches an interactive terminal interface where you can:
@@ -542,7 +540,7 @@ python -m crackerjack -v
542
540
  For the most comprehensive error details with visual formatting, combine verbose mode with the Rich UI:
543
541
 
544
542
  ```bash
545
- python -m crackerjack --interactive -v
543
+ python -m crackerjack -i -v
546
544
  ```
547
545
 
548
546
  ## Python 3.13+ Features
@@ -606,7 +604,7 @@ Crackerjack is designed with modern Python principles in mind:
606
604
  - **bandit:** For finding security vulnerabilities.
607
605
  - **vulture:** For dead code detection.
608
606
  - **creosote:** For unused dependency detection.
609
- - **flynt:** For f-string conversion.
607
+ - **complexipy:** For code complexity analysis.
610
608
  - **codespell:** For spelling correction.
611
609
  - **autotyping:** For automatically adding type hints.
612
610
  - **refurb:** For code improvement suggestions.
@@ -58,7 +58,7 @@ If you're new to Crackerjack, follow these steps:
58
58
 
59
59
  Or use the interactive Rich UI:
60
60
  ```
61
- python -m crackerjack --interactive
61
+ python -m crackerjack -i
62
62
  ```
63
63
 
64
64
  ---
@@ -116,7 +116,7 @@ Crackerjack automatically installs and manages these pre-commit hooks:
116
116
  3. **Ruff:** [Ruff](https://github.com/astral-sh/ruff) for linting, code formatting, and general code style enforcement.
117
117
  4. **Vulture:** [Vulture](https://github.com/jendrikseipp/vulture) to identify dead code.
118
118
  5. **Creosote:** [Creosote](https://github.com/fredrikaverpil/creosote) to detect unused dependencies.
119
- 6. **Flynt:** [Flynt](https://github.com/ikamensh/flynt/) for converting string formatting to f-strings.
119
+ 6. **Complexipy:** [Complexipy](https://github.com/rohaquinlop/complexipy-pre-commit) for analyzing code complexity.
120
120
  7. **Codespell:** [Codespell](https://github.com/codespell-project/codespell) for correcting typos in the code.
121
121
  8. **Autotyping:** [Autotyping](https://github.com/JelleZijlstra/autotyping) for adding type hints.
122
122
  9. **Refurb:** [Refurb](https://github.com/dosisod/refurb) to suggest code improvements.
@@ -225,7 +225,7 @@ python -m crackerjack -t --benchmark-regression --benchmark-regression-threshold
225
225
 
226
226
  Or with the interactive Rich UI:
227
227
  ```
228
- python -m crackerjack --interactive
228
+ python -m crackerjack -i
229
229
  ```
230
230
 
231
231
  ## Usage
@@ -257,7 +257,6 @@ class MyOptions:
257
257
  # Configuration options
258
258
  self.no_config_updates = False # Skip updating config files
259
259
  self.update_precommit = False # Update pre-commit hooks
260
- self.doc = False # Generate documentation (not implemented yet)
261
260
 
262
261
  # Process options
263
262
  self.clean = True # Clean code (remove docstrings, comments, etc.)
@@ -303,7 +302,6 @@ runner.process(MyOptions())
303
302
  - `-i`, `--interactive`: Run pre-commit hooks interactively when possible.
304
303
  - `-n`, `--no-config-updates`: Skip updating configuration files (e.g., `pyproject.toml`).
305
304
  - `-u`, `--update-precommit`: Update pre-commit hooks to the latest versions.
306
- - `-d`, `--doc`: Generate documentation. (not yet implemented)
307
305
  - `-v`, `--verbose`: Enable verbose output.
308
306
  - `-p`, `--publish <micro|minor|major>`: Bump the project version and publish to PyPI using PDM.
309
307
  - `-b`, `--bump <micro|minor|major>`: Bump the project version without publishing.
@@ -317,7 +315,7 @@ runner.process(MyOptions())
317
315
  - `--benchmark-regression`: Fail tests if benchmarks regress beyond threshold.
318
316
  - `--benchmark-regression-threshold`: Set threshold percentage for benchmark regression (default 5.0%).
319
317
  - `-a`, `--all`: Run with `-x -t -p <micro|minor|major> -c` development options.
320
- - `--interactive`: Enable the interactive Rich UI for a more user-friendly experience with visual progress tracking and interactive prompts.
318
+ - `-i`, `--interactive`: Enable the interactive Rich UI for a more user-friendly experience with visual progress tracking and interactive prompts.
321
319
  - `--ai-agent`: Enable AI agent mode with structured output (see [AI Agent Integration](#ai-agent-integration)).
322
320
  - `--help`: Display help.
323
321
 
@@ -417,7 +415,7 @@ runner.process(MyOptions())
417
415
 
418
416
  - **Rich Interactive Mode** - Run with the interactive Rich UI:
419
417
  ```bash
420
- python -m crackerjack --interactive
418
+ python -m crackerjack -i
421
419
  ```
422
420
 
423
421
  - **AI Integration** - Run with structured output for AI tools:
@@ -456,10 +454,10 @@ Crackerjack now offers an enhanced interactive experience through its Rich UI:
456
454
  - **Error Visualization:** Errors are presented in a structured, easy-to-understand format with recovery suggestions
457
455
  - **File Selection:** Interactive file browser for operations that require selecting files
458
456
 
459
- To use the Rich UI, run Crackerjack with the `--interactive` flag:
457
+ To use the Rich UI, run Crackerjack with the `-i` flag:
460
458
 
461
459
  ```bash
462
- python -m crackerjack --interactive
460
+ python -m crackerjack -i
463
461
  ```
464
462
 
465
463
  This launches an interactive terminal interface where you can:
@@ -498,7 +496,7 @@ python -m crackerjack -v
498
496
  For the most comprehensive error details with visual formatting, combine verbose mode with the Rich UI:
499
497
 
500
498
  ```bash
501
- python -m crackerjack --interactive -v
499
+ python -m crackerjack -i -v
502
500
  ```
503
501
 
504
502
  ## Python 3.13+ Features
@@ -562,7 +560,7 @@ Crackerjack is designed with modern Python principles in mind:
562
560
  - **bandit:** For finding security vulnerabilities.
563
561
  - **vulture:** For dead code detection.
564
562
  - **creosote:** For unused dependency detection.
565
- - **flynt:** For f-string conversion.
563
+ - **complexipy:** For code complexity analysis.
566
564
  - **codespell:** For spelling correction.
567
565
  - **autotyping:** For automatically adding type hints.
568
566
  - **refurb:** For code improvement suggestions.
@@ -14,11 +14,6 @@ repos:
14
14
  - id: check-added-large-files
15
15
  name: check-added-large-files
16
16
 
17
- - repo: https://github.com/abravalheri/validate-pyproject
18
- rev: v0.24.1
19
- hooks:
20
- - id: validate-pyproject
21
-
22
17
  - repo: https://github.com/tox-dev/pyproject-fmt
23
18
  rev: "v2.6.0"
24
19
  hooks:
@@ -34,7 +29,7 @@ repos:
34
29
  - keyring
35
30
 
36
31
  - repo: https://github.com/astral-sh/uv-pre-commit
37
- rev: 0.7.15
32
+ rev: 0.7.16
38
33
  hooks:
39
34
  - id: uv-lock
40
35
  files: ^pyproject\.toml$
@@ -110,14 +105,3 @@ repos:
110
105
  rev: v1.1.402
111
106
  hooks:
112
107
  - id: pyright
113
-
114
- # - repo: https://github.com/pdoc3/pdoc
115
- # rev: master
116
- # hooks:
117
- # - id: pdoc
118
- # name: pdoc
119
- # entry: pdoc --html -f -o docs module1 module2 module3
120
- # language_version: python3.11
121
- # require_serial: true
122
- # types: [ python ]
123
- # always_run: true
@@ -1,4 +1,5 @@
1
1
  import typing as t
2
+
2
3
  from .crackerjack import Crackerjack, create_crackerjack_runner
3
4
  from .errors import (
4
5
  CleaningError,
@@ -1,4 +1,5 @@
1
1
  from enum import Enum
2
+
2
3
  import typer
3
4
  from pydantic import BaseModel, field_validator
4
5
  from rich.console import Console
@@ -22,7 +23,6 @@ class BumpOption(str, Enum):
22
23
  class Options(BaseModel):
23
24
  commit: bool = False
24
25
  interactive: bool = False
25
- doc: bool = False
26
26
  no_config_updates: bool = False
27
27
  publish: BumpOption | None = None
28
28
  bump: BumpOption | None = None
@@ -62,7 +62,6 @@ cli_options = {
62
62
  "--interactive",
63
63
  help="Use the interactive Rich UI for a better experience.",
64
64
  ),
65
- "doc": typer.Option(False, "-d", "--doc", help="Generate documentation."),
66
65
  "no_config_updates": typer.Option(
67
66
  False, "-n", "--no-config-updates", help="Do not update configuration files."
68
67
  ),
@@ -145,7 +144,6 @@ cli_options = {
145
144
  def main(
146
145
  commit: bool = cli_options["commit"],
147
146
  interactive: bool = cli_options["interactive"],
148
- doc: bool = cli_options["doc"],
149
147
  no_config_updates: bool = cli_options["no_config_updates"],
150
148
  update_precommit: bool = cli_options["update_precommit"],
151
149
  verbose: bool = cli_options["verbose"],
@@ -168,7 +166,6 @@ def main(
168
166
  options = Options(
169
167
  commit=commit,
170
168
  interactive=interactive,
171
- doc=doc,
172
169
  no_config_updates=no_config_updates,
173
170
  update_precommit=update_precommit,
174
171
  verbose=verbose,
@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  from subprocess import CompletedProcess
7
7
  from subprocess import run as execute
8
8
  from tomllib import loads
9
+
9
10
  from pydantic import BaseModel
10
11
  from rich.console import Console
11
12
  from tomli_w import dumps
@@ -31,7 +32,6 @@ class CommandRunner(t.Protocol):
31
32
  class OptionsProtocol(t.Protocol):
32
33
  commit: bool
33
34
  interactive: bool
34
- doc: bool
35
35
  no_config_updates: bool
36
36
  verbose: bool
37
37
  update_precommit: bool
@@ -169,9 +169,12 @@ class CodeCleaner(BaseModel, arbitrary_types_allowed=True):
169
169
  cleaned_lines = []
170
170
  docstring_state = self._initialize_docstring_state()
171
171
  for i, line in enumerate(lines):
172
- _, result_line = self._process_line(lines, i, line, docstring_state)
173
- if result_line:
174
- cleaned_lines.append(result_line)
172
+ handled, result_line = self._process_line(lines, i, line, docstring_state)
173
+ if handled:
174
+ if result_line is not None:
175
+ cleaned_lines.append(result_line)
176
+ else:
177
+ cleaned_lines.append(line)
175
178
  return "\n".join(cleaned_lines)
176
179
 
177
180
  def _is_function_or_class_definition(self, stripped_line: str) -> bool:
@@ -287,13 +290,15 @@ class CodeCleaner(BaseModel, arbitrary_types_allowed=True):
287
290
  lines = code.split("\n")
288
291
  cleaned_lines = []
289
292
  function_tracker = {"in_function": False, "function_indent": 0}
293
+ import_tracker = {"in_imports": False, "last_import_type": None}
290
294
  for i, line in enumerate(lines):
291
295
  line = line.rstrip()
292
296
  stripped_line = line.lstrip()
293
297
  self._update_function_state(line, stripped_line, function_tracker)
298
+ self._update_import_state(line, stripped_line, import_tracker)
294
299
  if not line:
295
300
  if self._should_skip_empty_line(
296
- i, lines, cleaned_lines, function_tracker
301
+ i, lines, cleaned_lines, function_tracker, import_tracker
297
302
  ):
298
303
  continue
299
304
  cleaned_lines.append(line)
@@ -309,6 +314,113 @@ class CodeCleaner(BaseModel, arbitrary_types_allowed=True):
309
314
  function_tracker["in_function"] = False
310
315
  function_tracker["function_indent"] = 0
311
316
 
317
+ def _update_import_state(
318
+ self, line: str, stripped_line: str, import_tracker: dict[str, t.Any]
319
+ ) -> None:
320
+ if stripped_line.startswith(("import ", "from ")):
321
+ import_tracker["in_imports"] = True
322
+ if self._is_stdlib_import(stripped_line):
323
+ current_type = "stdlib"
324
+ elif self._is_local_import(stripped_line):
325
+ current_type = "local"
326
+ else:
327
+ current_type = "third_party"
328
+ import_tracker["last_import_type"] = current_type
329
+ elif stripped_line and not stripped_line.startswith("#"):
330
+ import_tracker["in_imports"] = False
331
+ import_tracker["last_import_type"] = None
332
+
333
+ def _is_stdlib_import(self, stripped_line: str) -> bool:
334
+ try:
335
+ if stripped_line.startswith("from "):
336
+ module = stripped_line.split()[1].split(".")[0]
337
+ else:
338
+ module = stripped_line.split()[1].split(".")[0]
339
+ except IndexError:
340
+ return False
341
+ stdlib_modules = {
342
+ "os",
343
+ "sys",
344
+ "re",
345
+ "json",
346
+ "datetime",
347
+ "time",
348
+ "pathlib",
349
+ "typing",
350
+ "collections",
351
+ "itertools",
352
+ "functools",
353
+ "operator",
354
+ "math",
355
+ "random",
356
+ "uuid",
357
+ "urllib",
358
+ "http",
359
+ "html",
360
+ "xml",
361
+ "email",
362
+ "csv",
363
+ "sqlite3",
364
+ "subprocess",
365
+ "threading",
366
+ "multiprocessing",
367
+ "asyncio",
368
+ "contextlib",
369
+ "dataclasses",
370
+ "enum",
371
+ "abc",
372
+ "io",
373
+ "tempfile",
374
+ "shutil",
375
+ "glob",
376
+ "pickle",
377
+ "copy",
378
+ "heapq",
379
+ "bisect",
380
+ "array",
381
+ "struct",
382
+ "zlib",
383
+ "hashlib",
384
+ "hmac",
385
+ "secrets",
386
+ "base64",
387
+ "binascii",
388
+ "codecs",
389
+ "locale",
390
+ "platform",
391
+ "socket",
392
+ "ssl",
393
+ "ipaddress",
394
+ "logging",
395
+ "warnings",
396
+ "inspect",
397
+ "ast",
398
+ "dis",
399
+ "tokenize",
400
+ "keyword",
401
+ "linecache",
402
+ "traceback",
403
+ "weakref",
404
+ "gc",
405
+ "ctypes",
406
+ "unittest",
407
+ "doctest",
408
+ "pdb",
409
+ "profile",
410
+ "cProfile",
411
+ "timeit",
412
+ "trace",
413
+ "calendar",
414
+ "decimal",
415
+ "fractions",
416
+ "statistics",
417
+ "tomllib",
418
+ }
419
+ return module in stdlib_modules
420
+
421
+ def _is_local_import(self, stripped_line: str) -> bool:
422
+ return stripped_line.startswith("from .") or " . " in stripped_line
423
+
312
424
  def _is_function_end(
313
425
  self, line: str, stripped_line: str, function_tracker: dict[str, t.Any]
314
426
  ) -> bool:
@@ -325,13 +437,44 @@ class CodeCleaner(BaseModel, arbitrary_types_allowed=True):
325
437
  lines: list[str],
326
438
  cleaned_lines: list[str],
327
439
  function_tracker: dict[str, t.Any],
440
+ import_tracker: dict[str, t.Any],
328
441
  ) -> bool:
329
442
  if line_idx > 0 and cleaned_lines and (not cleaned_lines[-1]):
330
443
  return True
444
+
445
+ if self._is_import_section_separator(line_idx, lines, import_tracker):
446
+ return False
447
+
331
448
  if function_tracker["in_function"]:
332
449
  return self._should_skip_function_empty_line(line_idx, lines)
333
450
  return False
334
451
 
452
+ def _is_import_section_separator(
453
+ self, line_idx: int, lines: list[str], import_tracker: dict[str, t.Any]
454
+ ) -> bool:
455
+ if not import_tracker["in_imports"]:
456
+ return False
457
+
458
+ next_line_idx = line_idx + 1
459
+ while next_line_idx < len(lines) and not lines[next_line_idx].strip():
460
+ next_line_idx += 1
461
+
462
+ if next_line_idx >= len(lines):
463
+ return False
464
+
465
+ next_line = lines[next_line_idx].strip()
466
+ if not next_line.startswith(("import ", "from ")):
467
+ return False
468
+
469
+ if self._is_stdlib_import(next_line):
470
+ next_type = "stdlib"
471
+ elif self._is_local_import(next_line):
472
+ next_type = "local"
473
+ else:
474
+ next_type = "third_party"
475
+
476
+ return import_tracker["last_import_type"] != next_type
477
+
335
478
  def _should_skip_function_empty_line(self, line_idx: int, lines: list[str]) -> bool:
336
479
  next_line_idx = line_idx + 1
337
480
  if next_line_idx >= len(lines):
@@ -2,6 +2,7 @@ import sys
2
2
  import typing as t
3
3
  from enum import Enum
4
4
  from pathlib import Path
5
+
5
6
  from rich.console import Console
6
7
  from rich.panel import Panel
7
8
 
@@ -2,6 +2,7 @@ import time
2
2
  import typing as t
3
3
  from enum import Enum, auto
4
4
  from pathlib import Path
5
+
5
6
  from rich.box import ROUNDED
6
7
  from rich.console import Console
7
8
  from rich.layout import Layout
@@ -18,6 +19,7 @@ from rich.prompt import Confirm, Prompt
18
19
  from rich.table import Table
19
20
  from rich.text import Text
20
21
  from rich.tree import Tree
22
+
21
23
  from .errors import CrackerjackError, ErrorCode, handle_error
22
24
 
23
25
 
@@ -4,7 +4,7 @@ requires = [ "pdm-backend" ]
4
4
 
5
5
  [project]
6
6
  name = "crackerjack"
7
- version = "0.21.6"
7
+ version = "0.21.8"
8
8
  description = "Crackerjack: code quality toolkit"
9
9
  readme = "README.md"
10
10
  keywords = [
@@ -6,7 +6,7 @@ requires = [
6
6
 
7
7
  [project]
8
8
  name = "crackerjack"
9
- version = "0.21.7"
9
+ version = "0.22.0"
10
10
  description = "Crackerjack: code quality toolkit"
11
11
  readme = "README.md"
12
12
  keywords = [
@@ -2,6 +2,7 @@ import os
2
2
  import time
3
3
  import typing as t
4
4
  from pathlib import Path
5
+
5
6
  import pytest
6
7
  from pytest import Config, Item, Parser
7
8
 
@@ -6,6 +6,7 @@ from dataclasses import dataclass
6
6
  from enum import Enum
7
7
  from pathlib import Path
8
8
  from unittest.mock import MagicMock, patch
9
+
9
10
  import pytest
10
11
  from rich.console import Console
11
12
  from crackerjack.crackerjack import (
@@ -1067,6 +1068,7 @@ class TestCrackerjackProcess:
1067
1068
 
1068
1069
  def test_code_cleaner_remove_docstrings(self) -> None:
1069
1070
  import ast
1071
+
1070
1072
  from rich.console import Console
1071
1073
  from crackerjack.crackerjack import CodeCleaner
1072
1074
 
@@ -1093,6 +1095,7 @@ class TestCrackerjackProcess:
1093
1095
 
1094
1096
  def test_code_cleaner_remove_docstrings_empty_functions(self) -> None:
1095
1097
  import ast
1098
+
1096
1099
  from rich.console import Console
1097
1100
  from crackerjack.crackerjack import CodeCleaner
1098
1101
 
@@ -1124,6 +1127,7 @@ class TestClass:
1124
1127
 
1125
1128
  def test_code_cleaner_remove_line_comments(self) -> None:
1126
1129
  from pathlib import Path
1130
+
1127
1131
  from rich.console import Console
1128
1132
  from crackerjack.crackerjack import CodeCleaner
1129
1133
 
@@ -2,6 +2,7 @@ import tempfile
2
2
  import typing as t
3
3
  from pathlib import Path
4
4
  from unittest.mock import MagicMock, patch
5
+
5
6
  import pytest
6
7
  from rich.console import Console
7
8
  from crackerjack import create_crackerjack_runner
@@ -12,7 +13,6 @@ class MockOptions:
12
13
  def __init__(self, **kwargs: t.Any) -> None:
13
14
  self.commit = kwargs.get("commit", False)
14
15
  self.interactive = kwargs.get("interactive", False)
15
- self.doc = kwargs.get("doc", False)
16
16
  self.no_config_updates = kwargs.get("no_config_updates", False)
17
17
  self.verbose = kwargs.get("verbose", False)
18
18
  self.update_precommit = kwargs.get("update_precommit", False)
@@ -1,5 +1,6 @@
1
1
  import typing as t
2
2
  from unittest.mock import MagicMock, patch
3
+
3
4
  import pytest
4
5
  from rich.console import Console
5
6
  from crackerjack.errors import (
@@ -2,6 +2,7 @@ import io
2
2
  import time
3
3
  from pathlib import Path
4
4
  from unittest.mock import MagicMock, patch
5
+
5
6
  import pytest
6
7
  from rich.console import Console
7
8
  from rich.panel import Panel
@@ -1,4 +1,5 @@
1
1
  from unittest.mock import MagicMock, patch
2
+
2
3
  import pytest
3
4
  from rich.console import Console
4
5
  from crackerjack.errors import ErrorCode, ExecutionError
@@ -1,5 +1,6 @@
1
1
  import typing as t
2
2
  from unittest.mock import MagicMock, patch
3
+
3
4
  import pytest
4
5
  from typer.testing import CliRunner
5
6
  from crackerjack.__main__ import BumpOption, Options, app
@@ -26,7 +27,6 @@ def test_no_options(runner: CliRunner, mock_crackerjack_process: MagicMock) -> N
26
27
  assert isinstance(options, Options)
27
28
  assert not options.commit
28
29
  assert not options.interactive
29
- assert not options.doc
30
30
  assert not options.update_precommit
31
31
  assert not options.no_config_updates
32
32
  assert options.publish is None
@@ -65,19 +65,6 @@ def test_interactive_option(
65
65
  mock_crackerjack_process.process.assert_not_called()
66
66
 
67
67
 
68
- def test_doc_option(runner: CliRunner, mock_crackerjack_process: MagicMock) -> None:
69
- result = runner.invoke(app, ["-d"])
70
- assert result.exit_code == 0
71
- mock_crackerjack_process.process.assert_called_once()
72
- options = mock_crackerjack_process.process.call_args[0][0]
73
- assert options.doc
74
- mock_crackerjack_process.process.reset_mock()
75
- result = runner.invoke(app, ["--doc"])
76
- assert result.exit_code == 0
77
- options = mock_crackerjack_process.process.call_args[0][0]
78
- assert options.doc
79
-
80
-
81
68
  def test_update_precommit_option(
82
69
  runner: CliRunner, mock_crackerjack_process: MagicMock
83
70
  ) -> None:
@@ -197,17 +184,16 @@ def test_multiple_options(
197
184
  runner: CliRunner, mock_crackerjack_process: MagicMock
198
185
  ) -> None:
199
186
  with patch("crackerjack.interactive.launch_interactive_cli") as mock_interactive:
200
- result = runner.invoke(app, ["-c", "-i", "-d", "-t", "-x"])
187
+ result = runner.invoke(app, ["-c", "-i", "-t", "-x"])
201
188
  assert result.exit_code == 0
202
189
  mock_interactive.assert_called_once()
203
190
  mock_crackerjack_process.process.assert_not_called()
204
- result = runner.invoke(app, ["-c", "-d", "-t", "-x"])
191
+ result = runner.invoke(app, ["-c", "-t", "-x"])
205
192
  assert result.exit_code == 0
206
193
  mock_crackerjack_process.process.assert_called_once()
207
194
  options = mock_crackerjack_process.process.call_args[0][0]
208
195
  assert options.commit
209
196
  assert not options.interactive
210
- assert options.doc
211
197
  assert options.test
212
198
  assert options.clean
213
199
 
@@ -216,7 +202,6 @@ def test_create_options() -> None:
216
202
  test_options = Options(
217
203
  commit=True,
218
204
  interactive=True,
219
- doc=True,
220
205
  no_config_updates=True,
221
206
  update_precommit=True,
222
207
  verbose=True,
@@ -230,7 +215,6 @@ def test_create_options() -> None:
230
215
  )
231
216
  assert test_options.commit
232
217
  assert test_options.interactive
233
- assert test_options.doc
234
218
  assert test_options.no_config_updates
235
219
  assert test_options.update_precommit
236
220
  assert test_options.verbose
@@ -1,6 +1,7 @@
1
1
  """Test cases for multiline function definitions in docstring removal."""
2
2
 
3
3
  import ast
4
+
4
5
  from rich.console import Console
5
6
  from crackerjack.crackerjack import CodeCleaner
6
7
 
@@ -2,6 +2,7 @@ import subprocess
2
2
  from pathlib import Path
3
3
  from typing import Any
4
4
  from unittest import mock
5
+
5
6
  from crackerjack.py313 import (
6
7
  CommandResult,
7
8
  CommandRunner,
@@ -1,4 +1,5 @@
1
1
  from pathlib import Path
2
+
2
3
  from crackerjack.py313 import (
3
4
  CommandResult,
4
5
  HookResult,
@@ -1,4 +1,5 @@
1
1
  import time
2
+
2
3
  import pytest
3
4
 
4
5
 
@@ -2,6 +2,7 @@ import io
2
2
  import typing as t
3
3
  from pathlib import Path
4
4
  from unittest.mock import MagicMock, patch
5
+
5
6
  import pytest
6
7
  from rich.console import Console
7
8
 
File without changes