crackerjack 0.29.0__tar.gz → 0.30.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 crackerjack might be problematic. Click here for more details.
- crackerjack-0.30.3/.crackerjack-hooks-updated +1 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/CLAUDE.md +364 -17
- {crackerjack-0.29.0 → crackerjack-0.30.3}/PKG-INFO +2 -1
- {crackerjack-0.29.0 → crackerjack-0.30.3}/RULES.md +98 -1
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/__main__.py +48 -2
- crackerjack-0.30.3/crackerjack/code_cleaner.py +980 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/crackerjack.py +713 -1048
- crackerjack-0.30.3/crackerjack/dynamic_config.py +586 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3/crackerjack}/pyproject.toml +2 -1
- {crackerjack-0.29.0/crackerjack → crackerjack-0.30.3}/pyproject.toml +2 -1
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_crackerjack.py +185 -62
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_crackerjack_runner.py +9 -1
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_structured_errors.py +5 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/uv.lock +46 -4
- crackerjack-0.29.0/.pre-commit-config-ai.yaml +0 -149
- crackerjack-0.29.0/.pre-commit-config-fast.yaml +0 -69
- crackerjack-0.29.0/.pre-commit-config.yaml +0 -114
- crackerjack-0.29.0/crackerjack/.pre-commit-config-ai.yaml +0 -149
- crackerjack-0.29.0/crackerjack/.pre-commit-config-fast.yaml +0 -69
- crackerjack-0.29.0/crackerjack/.pre-commit-config.yaml +0 -114
- {crackerjack-0.29.0 → crackerjack-0.30.3}/.envrc +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/.github/FUNDING.yml +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/.gitignore +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/.libcst.codemod.yaml +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/LICENSE +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/README-AI-AGENT.md +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/README.md +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/.gitignore +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/.libcst.codemod.yaml +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/.pdm.toml +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/__init__.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/errors.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/interactive.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/py313.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/TESTING.md +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/__init__.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/conftest.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/data/comments_sample.txt +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/data/docstrings_sample.txt +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/data/expected_comments_sample.txt +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/data/init.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_errors.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_interactive.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_interactive_run.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_main.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_multiline_functions.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_py313_advanced.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_py313_features.py +0 -0
- {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_pytest_features.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1752736926.5130398
|
|
@@ -200,6 +200,12 @@ python -m crackerjack -p major
|
|
|
200
200
|
python -m crackerjack -b patch
|
|
201
201
|
python -m crackerjack -b minor
|
|
202
202
|
python -m crackerjack -b major
|
|
203
|
+
|
|
204
|
+
# Skip git tag creation during version bumping
|
|
205
|
+
python -m crackerjack -p patch --no-git-tags
|
|
206
|
+
|
|
207
|
+
# Skip version consistency verification
|
|
208
|
+
python -m crackerjack -c --skip-version-check
|
|
203
209
|
```
|
|
204
210
|
|
|
205
211
|
#### PyPI Authentication Setup
|
|
@@ -281,6 +287,46 @@ python -m crackerjack -c
|
|
|
281
287
|
python -m crackerjack -r
|
|
282
288
|
```
|
|
283
289
|
|
|
290
|
+
### Git Tagging for Dependency Tracking
|
|
291
|
+
|
|
292
|
+
Crackerjack automatically creates git tags when bumping versions to enable proper dependency tracking:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# Version bumping automatically creates git tags
|
|
296
|
+
python -m crackerjack -p patch # Creates tag v1.0.1
|
|
297
|
+
python -m crackerjack -b minor # Creates tag v1.1.0
|
|
298
|
+
|
|
299
|
+
# Skip automatic git tagging
|
|
300
|
+
python -m crackerjack -p patch --no-git-tags
|
|
301
|
+
|
|
302
|
+
# Full workflow with automatic tagging
|
|
303
|
+
python -m crackerjack -a patch # Clean, test, bump, tag, commit, publish
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Git Tag Features:**
|
|
307
|
+
|
|
308
|
+
- **Automatic creation**: Tags are created after version bumping
|
|
309
|
+
- **Semantic naming**: Tags follow `v{version}` format (e.g., `v1.2.3`)
|
|
310
|
+
- **Descriptive messages**: Each tag includes package name and version
|
|
311
|
+
- **Duplicate prevention**: Skips tag creation if tag already exists
|
|
312
|
+
- **Automatic pushing**: Tags are pushed to remote during commit workflow
|
|
313
|
+
- **Dependency tracking**: Enables precise dependency management across projects
|
|
314
|
+
|
|
315
|
+
**Tag Workflow:**
|
|
316
|
+
|
|
317
|
+
1. Version is bumped using `uv version --bump {type}`
|
|
318
|
+
1. Git tag is created with format `v{new_version}`
|
|
319
|
+
1. Tag message includes package name and version
|
|
320
|
+
1. During commit, tags are pushed to remote repository
|
|
321
|
+
1. PyPI publishing can reference exact git commit via tag
|
|
322
|
+
|
|
323
|
+
**Version Verification:**
|
|
324
|
+
|
|
325
|
+
- Before committing: Verifies pyproject.toml version matches latest git tag
|
|
326
|
+
- Before publishing: Ensures version consistency for reliable dependency tracking
|
|
327
|
+
- Prevents publishing mismatched versions that could break dependency resolution
|
|
328
|
+
- Can be disabled with `--skip-version-check` for edge cases
|
|
329
|
+
|
|
284
330
|
## Project Architecture
|
|
285
331
|
|
|
286
332
|
Crackerjack is designed with modern Python principles and consists of several key components:
|
|
@@ -297,13 +343,16 @@ Crackerjack is designed with modern Python principles and consists of several ke
|
|
|
297
343
|
- Handles Git operations
|
|
298
344
|
- Integrates with Rich console for status output
|
|
299
345
|
|
|
300
|
-
1. **CodeCleaner
|
|
346
|
+
1. **CodeCleaner** (`code_cleaner.py`): Asynchronous code cleaning with intelligent optimization
|
|
301
347
|
|
|
302
348
|
- Removes docstrings (with syntax-aware pass statement insertion)
|
|
303
349
|
- Removes line comments
|
|
304
350
|
- Removes extra whitespace
|
|
305
351
|
- Reformats code using Ruff
|
|
306
352
|
- Handles file encoding issues gracefully
|
|
353
|
+
- Analyzes workload characteristics for optimal processing
|
|
354
|
+
- Uses async I/O for efficient file operations
|
|
355
|
+
- Provides detailed progress reporting and error recovery
|
|
307
356
|
|
|
308
357
|
1. **ConfigManager**: Handles configuration file management
|
|
309
358
|
|
|
@@ -329,6 +378,9 @@ Crackerjack is designed with modern Python principles and consists of several ke
|
|
|
329
378
|
- **Protocol-Based Design**: Uses `t.Protocol` for interface definitions
|
|
330
379
|
- **Factory Pattern**: Employs a factory function (`create_crackerjack_runner`) for dependency injection
|
|
331
380
|
- **Command Pattern**: CLI commands are mapped to specific operations
|
|
381
|
+
- **Async Processing**: `CodeCleaner` uses asyncio for efficient file operations
|
|
382
|
+
- **Observer Pattern**: Progress tracking and session management for workflow monitoring
|
|
383
|
+
- **Strategy Pattern**: Dynamic configuration based on project size and characteristics
|
|
332
384
|
|
|
333
385
|
### Testing Infrastructure
|
|
334
386
|
|
|
@@ -369,23 +421,27 @@ Access interactive mode with: `python -m crackerjack -i`
|
|
|
369
421
|
|
|
370
422
|
## Module Organization
|
|
371
423
|
|
|
372
|
-
Crackerjack follows a
|
|
424
|
+
Crackerjack follows a modular architecture with clear separation of concerns:
|
|
373
425
|
|
|
374
426
|
### File Structure
|
|
375
427
|
|
|
376
|
-
- `crackerjack.py` - Main
|
|
377
|
-
- `
|
|
378
|
-
- `
|
|
379
|
-
- `
|
|
428
|
+
- `crackerjack.py` - Main orchestrator class containing core workflow logic
|
|
429
|
+
- `code_cleaner.py` - Async code cleaning with workload analysis and optimization
|
|
430
|
+
- `errors.py` - Structured error handling system with error codes and recovery suggestions
|
|
431
|
+
- `interactive.py` - Rich-based interactive UI implementation with progress tracking
|
|
432
|
+
- `py313.py` - Python 3.13+ specific feature detection and compatibility
|
|
433
|
+
- `dynamic_config.py` - Dynamic configuration management based on project characteristics
|
|
380
434
|
- `__main__.py` - Entry point for `python -m crackerjack`
|
|
381
435
|
|
|
382
436
|
### Key Implementation Details
|
|
383
437
|
|
|
384
|
-
- **
|
|
438
|
+
- **Modular Architecture**: Clear separation of concerns across specialized modules
|
|
439
|
+
- **Async Code Processing**: `code_cleaner.py` uses asyncio for efficient file processing
|
|
385
440
|
- **Type Safety**: Extensive use of protocols and type hints throughout
|
|
386
|
-
- **Error Handling**: Comprehensive error handling with structured error codes
|
|
441
|
+
- **Error Handling**: Comprehensive error handling with structured error codes and recovery suggestions
|
|
387
442
|
- **Dynamic Configuration**: Project size detection affects worker count, timeouts, and other settings
|
|
388
443
|
- **Rich Integration**: All console output uses Rich for enhanced terminal UI
|
|
444
|
+
- **Performance Optimization**: Workload analysis and dynamic scaling based on project characteristics
|
|
389
445
|
|
|
390
446
|
## CLI Reference
|
|
391
447
|
|
|
@@ -413,6 +469,8 @@ Crackerjack follows a single-file architecture for simplicity and maintainabilit
|
|
|
413
469
|
| `-p` | `--publish` | Bump version and publish to PyPI |
|
|
414
470
|
| `-b` | `--bump` | Bump version only (no publish) |
|
|
415
471
|
| `-a` | `--all` | Run full workflow: clean, test, publish, commit |
|
|
472
|
+
| | `--no-git-tags` | Skip creating git tags during version bumping |
|
|
473
|
+
| | `--skip-version-check` | Skip version consistency verification |
|
|
416
474
|
|
|
417
475
|
### Testing Options
|
|
418
476
|
|
|
@@ -479,6 +537,9 @@ Crackerjack follows a single-file architecture for simplicity and maintainabilit
|
|
|
479
537
|
- **CRITICAL**: Use tempfile module for temporary files in tests (never create files directly on filesystem)
|
|
480
538
|
- Use pytest's `tmp_path` and `tmp_path_factory` fixtures
|
|
481
539
|
- Tests should be isolated and not affect the surrounding environment
|
|
540
|
+
- **Async Testing**: Use `pytest-asyncio` for testing async operations in `code_cleaner.py`
|
|
541
|
+
- **Version Consistency**: Mock `_verify_version_consistency` in tests to avoid git tag conflicts
|
|
542
|
+
- **Protocol Testing**: Ensure all test mock objects implement complete protocol interfaces
|
|
482
543
|
|
|
483
544
|
1. **Dependencies**:
|
|
484
545
|
|
|
@@ -520,9 +581,11 @@ When generating code, AI assistants MUST follow these standards to ensure compli
|
|
|
520
581
|
```python
|
|
521
582
|
# Bad
|
|
522
583
|
if response in ["y", "yes", "ok"]:
|
|
584
|
+
pass
|
|
523
585
|
|
|
524
586
|
# Good
|
|
525
587
|
if response in ("y", "yes", "ok"):
|
|
588
|
+
pass
|
|
526
589
|
```
|
|
527
590
|
|
|
528
591
|
- **FURB120**: Don't pass arguments that are the same as the default value
|
|
@@ -567,7 +630,8 @@ When generating code, AI assistants MUST follow these standards to ensure compli
|
|
|
567
630
|
```python
|
|
568
631
|
# Bad - High complexity (>15)
|
|
569
632
|
def complex_method(self, data):
|
|
570
|
-
# 50+ lines with multiple nested if/else, loops, etc.
|
|
633
|
+
pass # 50+ lines with multiple nested if/else, loops, etc.
|
|
634
|
+
|
|
571
635
|
|
|
572
636
|
# Good - Broken into helpers
|
|
573
637
|
def main_method(self, data):
|
|
@@ -575,14 +639,17 @@ When generating code, AI assistants MUST follow these standards to ensure compli
|
|
|
575
639
|
result = self._apply_transformations(processed)
|
|
576
640
|
return self._finalize_result(result)
|
|
577
641
|
|
|
642
|
+
|
|
578
643
|
def _preprocess_data(self, data):
|
|
579
|
-
# Single responsibility
|
|
644
|
+
pass # Single responsibility
|
|
645
|
+
|
|
580
646
|
|
|
581
647
|
def _apply_transformations(self, data):
|
|
582
|
-
# Single responsibility
|
|
648
|
+
pass # Single responsibility
|
|
649
|
+
|
|
583
650
|
|
|
584
651
|
def _finalize_result(self, data):
|
|
585
|
-
# Single responsibility
|
|
652
|
+
pass # Single responsibility
|
|
586
653
|
```
|
|
587
654
|
|
|
588
655
|
**Example of good patterns:**
|
|
@@ -679,9 +746,12 @@ cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
|
|
|
679
746
|
```python
|
|
680
747
|
# Bad
|
|
681
748
|
def _format_task_detail(self, task) -> str:
|
|
749
|
+
pass
|
|
750
|
+
|
|
682
751
|
|
|
683
752
|
# Good
|
|
684
753
|
def _format_task_detail(self, task: TaskStatus) -> str:
|
|
754
|
+
pass
|
|
685
755
|
```
|
|
686
756
|
|
|
687
757
|
- **reportArgumentType**: Protocol implementations must match exactly
|
|
@@ -825,26 +895,77 @@ By following these guidelines during code generation, AI assistants will produce
|
|
|
825
895
|
- Add complete type annotations to ALL function parameters
|
|
826
896
|
- Keep cognitive complexity under 15 per function
|
|
827
897
|
- Implement ALL protocol properties when creating test classes
|
|
898
|
+
- **CRITICAL**: Use `tempfile.NamedTemporaryFile()` for temporary files, never hardcoded `/tmp/` paths
|
|
899
|
+
- **CRITICAL**: Chain return statements when possible (avoid intermediate variables before return)
|
|
900
|
+
- **CRITICAL**: Extract helper methods when functions exceed 15 cognitive complexity
|
|
828
901
|
|
|
829
902
|
1. **Common Patterns to Always Follow:**
|
|
830
903
|
|
|
831
904
|
```python
|
|
832
905
|
# Membership testing - ALWAYS use tuples
|
|
833
906
|
if status in ("pending", "completed", "failed"):
|
|
907
|
+
pass
|
|
834
908
|
|
|
835
909
|
# Optional parameters - Don't pass None when it's the default
|
|
836
910
|
value = kwargs.get("optional_param") # Good
|
|
837
911
|
value = kwargs.get("optional_param", None) # Bad
|
|
838
912
|
|
|
913
|
+
|
|
839
914
|
# Type annotations - ALWAYS complete
|
|
840
915
|
def helper_method(self, task: TaskStatus, datetime_module) -> str: # Good
|
|
916
|
+
pass
|
|
917
|
+
|
|
918
|
+
|
|
841
919
|
def helper_method(self, task) -> str: # Bad - missing type
|
|
920
|
+
pass
|
|
921
|
+
|
|
842
922
|
|
|
843
923
|
# Protocol implementation - ALL properties required
|
|
844
924
|
class TestOptions(OptionsProtocol):
|
|
845
925
|
verbose = True
|
|
846
926
|
resume_from: str | None = None # Required
|
|
847
927
|
progress_file: str | None = None # Required
|
|
928
|
+
experimental_hooks: bool = False # Required
|
|
929
|
+
enable_pyrefly: bool = False # Required
|
|
930
|
+
enable_ty: bool = False # Required
|
|
931
|
+
compress_docs: bool = False # Required
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
# Temporary files - ALWAYS use tempfile module
|
|
935
|
+
import tempfile
|
|
936
|
+
|
|
937
|
+
with tempfile.NamedTemporaryFile(suffix=".yaml", delete=False) as temp_file:
|
|
938
|
+
temp_path = temp_file.name # Good
|
|
939
|
+
temp_path = "/tmp/test-config.yaml" # Bad - hardcoded path
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
# Return statement chaining - avoid intermediate variables
|
|
943
|
+
def get_config() -> Config:
|
|
944
|
+
return ConfigGenerator().create_config() # Good
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
def get_config() -> Config: # Bad - unnecessary intermediate variable
|
|
948
|
+
generator = ConfigGenerator()
|
|
949
|
+
return generator.create_config()
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
# Complexity reduction - extract helper methods
|
|
953
|
+
def complex_function(data: dict) -> Result:
|
|
954
|
+
# Bad - high complexity (>15)
|
|
955
|
+
if condition1:
|
|
956
|
+
if condition2:
|
|
957
|
+
if condition3:
|
|
958
|
+
pass # ... many nested conditions
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
def complex_function(data: dict) -> Result: # Good - extracted helpers
|
|
962
|
+
if self._should_process(data):
|
|
963
|
+
return self._process_data(data)
|
|
964
|
+
return self._handle_error(data)
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
def _should_process(self, data: dict) -> bool:
|
|
968
|
+
return condition1 and condition2 and condition3
|
|
848
969
|
```
|
|
849
970
|
|
|
850
971
|
1. **Zen-Inspired Code Examples:**
|
|
@@ -900,10 +1021,74 @@ By following these guidelines during code generation, AI assistants will produce
|
|
|
900
1021
|
1. **Quality Gate Strategy:**
|
|
901
1022
|
|
|
902
1023
|
- Write code that would pass `python -m crackerjack --comprehensive` on first try
|
|
903
|
-
- Prioritize these checks: Refurb FURB109, FURB120, Pyright reportMissingParameterType, Complexipy \<
|
|
1024
|
+
- Prioritize these checks: Refurb FURB109, FURB120, FURB184, Pyright reportMissingParameterType, Complexipy \<15, Bandit B108
|
|
904
1025
|
- When refactoring complex code, break into 3-5 helper methods with single responsibilities
|
|
905
1026
|
- **Apply Zen principles**: Every function should be easily explainable in plain English
|
|
906
1027
|
|
|
1028
|
+
1. **Critical Error Prevention:**
|
|
1029
|
+
|
|
1030
|
+
**Bandit B108 (Hardcoded Temp Directory):**
|
|
1031
|
+
|
|
1032
|
+
```python
|
|
1033
|
+
# NEVER do this - causes security warnings
|
|
1034
|
+
config_path = "/tmp/test-config.yaml"
|
|
1035
|
+
|
|
1036
|
+
# ALWAYS use tempfile module
|
|
1037
|
+
import tempfile
|
|
1038
|
+
|
|
1039
|
+
with tempfile.NamedTemporaryFile(suffix=".yaml", delete=False) as temp_file:
|
|
1040
|
+
config_path = temp_file.name
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
**Refurb FURB184 (Return Statement Chaining):**
|
|
1044
|
+
|
|
1045
|
+
```python
|
|
1046
|
+
# AVOID - unnecessary intermediate variable
|
|
1047
|
+
def create_config() -> Config:
|
|
1048
|
+
generator = ConfigGenerator()
|
|
1049
|
+
return generator.create_config()
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
# PREFER - chained return statement
|
|
1053
|
+
def create_config() -> Config:
|
|
1054
|
+
return ConfigGenerator().create_config()
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
**Pyright Protocol Compatibility:**
|
|
1058
|
+
|
|
1059
|
+
```python
|
|
1060
|
+
# ALWAYS implement ALL protocol properties
|
|
1061
|
+
class TestOptions(OptionsProtocol):
|
|
1062
|
+
# Missing properties cause type errors
|
|
1063
|
+
verbose: bool = False
|
|
1064
|
+
experimental_hooks: bool = False # Don't forget new properties
|
|
1065
|
+
enable_pyrefly: bool = False
|
|
1066
|
+
enable_ty: bool = False
|
|
1067
|
+
compress_docs: bool = False
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
**Complexipy Complexity (>15):**
|
|
1071
|
+
|
|
1072
|
+
```python
|
|
1073
|
+
# AVOID - high complexity method
|
|
1074
|
+
def process_data(self, data: dict) -> Result:
|
|
1075
|
+
if condition1:
|
|
1076
|
+
if condition2:
|
|
1077
|
+
if condition3:
|
|
1078
|
+
pass # ... many nested conditions >15 complexity
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
# PREFER - extracted helper methods
|
|
1082
|
+
def process_data(self, data: dict) -> Result:
|
|
1083
|
+
if self._should_process(data):
|
|
1084
|
+
return self._handle_processing(data)
|
|
1085
|
+
return self._handle_error(data)
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
def _should_process(self, data: dict) -> bool:
|
|
1089
|
+
return condition1 and condition2 and condition3
|
|
1090
|
+
```
|
|
1091
|
+
|
|
907
1092
|
1. **Testing Integration:**
|
|
908
1093
|
|
|
909
1094
|
- All generated test classes MUST implement complete protocols
|
|
@@ -1025,6 +1210,15 @@ By maintaining these standards proactively, AI assistants will stay ahead of qua
|
|
|
1025
1210
|
|
|
1026
1211
|
## Recent Bug Fixes and Improvements
|
|
1027
1212
|
|
|
1213
|
+
### Current Project Status (July 2025)
|
|
1214
|
+
|
|
1215
|
+
- **Test Coverage**: 74.48% (exceeds 42% minimum requirement)
|
|
1216
|
+
- **Code Quality**: All 172 tests passing, 1 skipped
|
|
1217
|
+
- **Module Structure**: Refactored from single-file to modular architecture
|
|
1218
|
+
- **Async Processing**: Implemented async code cleaning for better performance
|
|
1219
|
+
- **Error Handling**: Enhanced with structured error codes and recovery suggestions
|
|
1220
|
+
- **Version Consistency**: Improved git tag integration and version verification
|
|
1221
|
+
|
|
1028
1222
|
### CodeCleaner Docstring Removal Fix (December 2024)
|
|
1029
1223
|
|
|
1030
1224
|
#### Problem Description
|
|
@@ -1251,6 +1445,156 @@ This enhancement ensures that the code cleaner (`-x` flag) can handle edge cases
|
|
|
1251
1445
|
|
|
1252
1446
|
**Never skip crackerjack verification** - it's the project's standard quality gate.
|
|
1253
1447
|
|
|
1448
|
+
## Test Coverage Improvement
|
|
1449
|
+
|
|
1450
|
+
**MANDATORY: AI assistants should incrementally improve test coverage when working on crackerjack projects.**
|
|
1451
|
+
|
|
1452
|
+
### Coverage Improvement Strategy
|
|
1453
|
+
|
|
1454
|
+
When working on any Python project with crackerjack, AI assistants should:
|
|
1455
|
+
|
|
1456
|
+
1. **Check current coverage**: Run `uv run pytest --cov=<package_name> --cov-report=term-missing` to see current coverage percentage
|
|
1457
|
+
1. **Identify improvement opportunities**: Look for uncovered lines in modules you're working on
|
|
1458
|
+
1. **Apply incremental improvements**: Add 1-3 tests per session that increase coverage by 2-5%
|
|
1459
|
+
1. **Focus on low-hanging fruit**: Prioritize easy wins like testing simple functions, error paths, and edge cases
|
|
1460
|
+
|
|
1461
|
+
### Coverage Improvement Guidelines
|
|
1462
|
+
|
|
1463
|
+
**When to improve coverage:**
|
|
1464
|
+
|
|
1465
|
+
- Coverage is below 100% for any package
|
|
1466
|
+
- You're working on or near code that lacks test coverage
|
|
1467
|
+
- You're debugging or fixing issues in untested areas
|
|
1468
|
+
- You're adding new features (always include tests)
|
|
1469
|
+
|
|
1470
|
+
**How to improve coverage efficiently:**
|
|
1471
|
+
|
|
1472
|
+
1. **Start with simple wins**: Test basic functions, property getters, simple methods
|
|
1473
|
+
1. **Test error paths**: Add tests for exception handling and error conditions
|
|
1474
|
+
1. **Test edge cases**: Cover boundary conditions, empty inputs, None values
|
|
1475
|
+
1. **Test integration points**: Cover method interactions and data flow
|
|
1476
|
+
|
|
1477
|
+
**Coverage improvement limits:**
|
|
1478
|
+
|
|
1479
|
+
- **Maximum 3 debugging attempts** per test: If a test doesn't work after 3 debugging passes, skip it and move on
|
|
1480
|
+
- **Time-boxed effort**: Don't spend more than 10-15 minutes on coverage improvement per session
|
|
1481
|
+
- **Incremental progress**: Aim for 2-5% coverage improvement per session, not perfection
|
|
1482
|
+
|
|
1483
|
+
### Example Coverage Improvement Workflow
|
|
1484
|
+
|
|
1485
|
+
```bash
|
|
1486
|
+
# Check current coverage
|
|
1487
|
+
uv run pytest --cov=mypackage --cov-report=term-missing
|
|
1488
|
+
|
|
1489
|
+
# Identify uncovered lines (look for lines marked with "Missing")
|
|
1490
|
+
# Example output:
|
|
1491
|
+
# mypackage/core.py 45 10 78% 23-25, 67-70, 89-92
|
|
1492
|
+
|
|
1493
|
+
# Add tests for uncovered lines:
|
|
1494
|
+
# - Line 23-25: Error handling in validate_input()
|
|
1495
|
+
# - Line 67-70: Edge case in process_data()
|
|
1496
|
+
# - Line 89-92: Exception path in save_results()
|
|
1497
|
+
|
|
1498
|
+
# Write focused tests
|
|
1499
|
+
def test_validate_input_empty_string():
|
|
1500
|
+
with pytest.raises(ValueError):
|
|
1501
|
+
validate_input("")
|
|
1502
|
+
|
|
1503
|
+
def test_process_data_none_input():
|
|
1504
|
+
result = process_data(None)
|
|
1505
|
+
assert result == []
|
|
1506
|
+
|
|
1507
|
+
def test_save_results_file_not_found():
|
|
1508
|
+
with pytest.raises(FileNotFoundError):
|
|
1509
|
+
save_results("/nonexistent/path")
|
|
1510
|
+
|
|
1511
|
+
# Re-run coverage to confirm improvement
|
|
1512
|
+
uv run pytest --cov=mypackage --cov-report=term-missing
|
|
1513
|
+
```
|
|
1514
|
+
|
|
1515
|
+
### Coverage Improvement Patterns
|
|
1516
|
+
|
|
1517
|
+
**Easy wins (prioritize these):**
|
|
1518
|
+
|
|
1519
|
+
- Property getters and setters
|
|
1520
|
+
- Simple validation functions
|
|
1521
|
+
- String formatting methods
|
|
1522
|
+
- Basic mathematical operations
|
|
1523
|
+
- Default parameter handling
|
|
1524
|
+
|
|
1525
|
+
**Medium effort:**
|
|
1526
|
+
|
|
1527
|
+
- Error handling paths
|
|
1528
|
+
- Conditional logic branches
|
|
1529
|
+
- Loop edge cases
|
|
1530
|
+
- File I/O operations
|
|
1531
|
+
- Configuration parsing
|
|
1532
|
+
|
|
1533
|
+
**Skip if complex (save for dedicated sessions):**
|
|
1534
|
+
|
|
1535
|
+
- Complex async operations
|
|
1536
|
+
- Integration with external services
|
|
1537
|
+
- Complex state management
|
|
1538
|
+
- Performance-critical paths
|
|
1539
|
+
- Legacy code with many dependencies
|
|
1540
|
+
|
|
1541
|
+
### Coverage Quality Standards
|
|
1542
|
+
|
|
1543
|
+
**Good coverage improvement:**
|
|
1544
|
+
|
|
1545
|
+
- Tests are simple and focused
|
|
1546
|
+
- Each test covers 1-3 lines of uncovered code
|
|
1547
|
+
- Tests are reliable and don't flake
|
|
1548
|
+
- Tests run quickly (< 1 second each)
|
|
1549
|
+
- Tests improve understanding of the code
|
|
1550
|
+
|
|
1551
|
+
**Poor coverage improvement (avoid):**
|
|
1552
|
+
|
|
1553
|
+
- Tests that are complex or hard to understand
|
|
1554
|
+
- Tests that mock too heavily or don't test real behavior
|
|
1555
|
+
- Tests that are flaky or timing-dependent
|
|
1556
|
+
- Tests that take a long time to run
|
|
1557
|
+
- Tests that duplicate existing coverage
|
|
1558
|
+
|
|
1559
|
+
### Coverage Improvement Examples
|
|
1560
|
+
|
|
1561
|
+
**✅ Good coverage improvement:**
|
|
1562
|
+
|
|
1563
|
+
```python
|
|
1564
|
+
def test_format_error_message_with_code():
|
|
1565
|
+
"""Test error message formatting with error code."""
|
|
1566
|
+
result = format_error_message("Invalid input", code="E001")
|
|
1567
|
+
assert result == "[E001] Invalid input"
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
def test_format_error_message_without_code():
|
|
1571
|
+
"""Test error message formatting without error code."""
|
|
1572
|
+
result = format_error_message("Invalid input")
|
|
1573
|
+
assert result == "Invalid input"
|
|
1574
|
+
```
|
|
1575
|
+
|
|
1576
|
+
**❌ Avoid complex coverage improvements:**
|
|
1577
|
+
|
|
1578
|
+
```python
|
|
1579
|
+
# Don't spend time on complex setups like this during regular work
|
|
1580
|
+
def test_complex_async_workflow_with_multiple_mocks():
|
|
1581
|
+
"""This test is too complex for incremental coverage improvement."""
|
|
1582
|
+
# 50+ lines of complex mocking and setup
|
|
1583
|
+
# Multiple async operations
|
|
1584
|
+
# Complex state management
|
|
1585
|
+
# Skip this during regular coverage improvement
|
|
1586
|
+
```
|
|
1587
|
+
|
|
1588
|
+
### Coverage Reporting
|
|
1589
|
+
|
|
1590
|
+
When you've improved coverage, report it briefly:
|
|
1591
|
+
|
|
1592
|
+
- "Improved coverage from 73% to 76% by adding tests for error handling paths"
|
|
1593
|
+
- "Added 3 tests covering previously untested validation functions"
|
|
1594
|
+
- "Coverage increased 4% with tests for edge cases in data processing"
|
|
1595
|
+
|
|
1596
|
+
**Remember**: The goal is steady, incremental improvement, not perfection. Focus on sustainable progress that makes the codebase more robust without derailing primary development tasks.
|
|
1597
|
+
|
|
1254
1598
|
## Pre-commit Hook Maintenance
|
|
1255
1599
|
|
|
1256
1600
|
### Monthly Maintenance Tasks
|
|
@@ -1297,12 +1641,12 @@ This enhancement ensures that the code cleaner (`-x` flag) can handle edge cases
|
|
|
1297
1641
|
- Includes: all checks + type analysis, complexity, dead code detection
|
|
1298
1642
|
- Command: `python -m crackerjack --comprehensive`
|
|
1299
1643
|
|
|
1300
|
-
**📦
|
|
1644
|
+
**📦 Manual Hook Execution:**
|
|
1301
1645
|
|
|
1302
|
-
- Expensive operations
|
|
1303
|
-
- Runs comprehensive analysis before pushing changes
|
|
1646
|
+
- Expensive operations run only when explicitly called via crackerjack
|
|
1304
1647
|
- Prevents performance bottlenecks during development
|
|
1305
|
-
-
|
|
1648
|
+
- No automatic git hooks installed - crackerjack handles all quality checks internally
|
|
1649
|
+
- Use `python -m crackerjack --comprehensive` to run all quality checks
|
|
1306
1650
|
|
|
1307
1651
|
### Hook Configuration Status (Last Audit: July 2025)
|
|
1308
1652
|
|
|
@@ -1317,6 +1661,9 @@ This enhancement ensures that the code cleaner (`-x` flag) can handle edge cases
|
|
|
1317
1661
|
|
|
1318
1662
|
- Non-critical type errors are still errors that need to be fixed to pass crackerjack validation
|
|
1319
1663
|
- test directory files need to pass pyright tests as well in order for crackerjack to successfully complete
|
|
1664
|
+
- When fixing tests, version consistency checks may need to be mocked or disabled in test scenarios
|
|
1665
|
+
- The codebase now achieves 74%+ test coverage across all modules
|
|
1666
|
+
- Tests include comprehensive coverage of error handling, async operations, and edge cases
|
|
1320
1667
|
|
|
1321
1668
|
## AI Agent Integration
|
|
1322
1669
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crackerjack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.30.3
|
|
4
4
|
Summary: Crackerjack: code quality toolkit
|
|
5
5
|
Project-URL: documentation, https://github.com/lesleslie/crackerjack
|
|
6
6
|
Project-URL: homepage, https://github.com/lesleslie/crackerjack
|
|
@@ -26,6 +26,7 @@ Requires-Python: >=3.13
|
|
|
26
26
|
Requires-Dist: aiofiles>=24.1
|
|
27
27
|
Requires-Dist: autotyping>=24.9
|
|
28
28
|
Requires-Dist: hatchling>=1.25
|
|
29
|
+
Requires-Dist: jinja2>=3.1
|
|
29
30
|
Requires-Dist: keyring>=25.6
|
|
30
31
|
Requires-Dist: pre-commit>=4.2
|
|
31
32
|
Requires-Dist: pydantic>=2.11.7
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
- Avoid unnecessary line comments - use them sparingly only for complex logic
|
|
28
28
|
- Use protocols (`t.Protocol`) instead of abstract base classes
|
|
29
29
|
- Choose clear, descriptive variable and function names that make the code self-documenting
|
|
30
|
+
- **Keep cognitive complexity under 15 per function** - extract helper methods if needed
|
|
30
31
|
|
|
31
32
|
- **Code Organization**
|
|
32
33
|
|
|
@@ -48,7 +49,72 @@
|
|
|
48
49
|
- Configure code with Ruff for linting and formatting
|
|
49
50
|
- Set up pre-commit hooks for consistent code quality
|
|
50
51
|
- Use UV for dependency management
|
|
51
|
-
|
|
52
|
+
|
|
53
|
+
## Critical Error Prevention
|
|
54
|
+
|
|
55
|
+
**Bandit B108 (Hardcoded Temp Directory):**
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
# NEVER do this - causes security warnings
|
|
59
|
+
config_path = "/tmp/test-config.yaml"
|
|
60
|
+
|
|
61
|
+
# ALWAYS use tempfile module
|
|
62
|
+
import tempfile
|
|
63
|
+
|
|
64
|
+
with tempfile.NamedTemporaryFile(suffix=".yaml", delete=False) as temp_file:
|
|
65
|
+
config_path = temp_file.name
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Refurb FURB184 (Return Statement Chaining):**
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
# AVOID - unnecessary intermediate variable
|
|
72
|
+
def create_config() -> Config:
|
|
73
|
+
generator = ConfigGenerator()
|
|
74
|
+
return generator.create_config()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# PREFER - chained return statement
|
|
78
|
+
def create_config() -> Config:
|
|
79
|
+
return ConfigGenerator().create_config()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Pyright Protocol Compatibility:**
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
# ALWAYS implement ALL protocol properties
|
|
86
|
+
class TestOptions(OptionsProtocol):
|
|
87
|
+
# Missing properties cause type errors
|
|
88
|
+
verbose: bool = False
|
|
89
|
+
experimental_hooks: bool = False # Don't forget new properties
|
|
90
|
+
enable_pyrefly: bool = False
|
|
91
|
+
enable_ty: bool = False
|
|
92
|
+
compress_docs: bool = False
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Complexipy Complexity (>15):**
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
# AVOID - high complexity method
|
|
99
|
+
def process_data(self, data: dict) -> Result:
|
|
100
|
+
if condition1:
|
|
101
|
+
if condition2:
|
|
102
|
+
if condition3:
|
|
103
|
+
pass # ... many nested conditions >15 complexity
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# PREFER - extracted helper methods
|
|
107
|
+
def process_data(self, data: dict) -> Result:
|
|
108
|
+
if self._should_process(data):
|
|
109
|
+
return self._handle_processing(data)
|
|
110
|
+
return self._handle_error(data)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _should_process(self, data: dict) -> bool:
|
|
114
|
+
return condition1 and condition2 and condition3
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- Implement pytest for testing with timeout handling
|
|
52
118
|
|
|
53
119
|
- **Use UV for Tool Execution**
|
|
54
120
|
|
|
@@ -184,6 +250,37 @@
|
|
|
184
250
|
- Use asyncio exclusively for async testing; do not test with trio compatibility
|
|
185
251
|
- Configure pytest with asyncio_mode="auto" for simpler async testing
|
|
186
252
|
|
|
253
|
+
- **Test Coverage Improvement (MANDATORY)**
|
|
254
|
+
|
|
255
|
+
- **Always improve coverage incrementally** when working on projects with pytest coverage below 100%
|
|
256
|
+
- **Check coverage first**: Run `uv run pytest --cov=<package_name> --cov-report=term-missing` to see current status
|
|
257
|
+
- **Target 2-5% improvement per session**: Add 1-3 focused tests that cover uncovered lines
|
|
258
|
+
- **Prioritize easy wins**: Test simple functions, error paths, edge cases, and validation logic
|
|
259
|
+
- **3-attempt rule**: If a test doesn't work after 3 debugging attempts, skip it and move on
|
|
260
|
+
- **Time-boxed effort**: Spend maximum 10-15 minutes on coverage improvement per session
|
|
261
|
+
- **Focus on low-hanging fruit**: Property getters, simple validation, string formatting, error handling
|
|
262
|
+
- **Avoid complex coverage improvements**: Skip async operations, external integrations, and complex state management
|
|
263
|
+
- **Write focused tests**: Each test should cover 1-3 lines of uncovered code
|
|
264
|
+
- **Quality over quantity**: Tests should be simple, reliable, and fast (< 1 second each)
|
|
265
|
+
- **Example incremental approach**:
|
|
266
|
+
```python
|
|
267
|
+
# Target: Cover error handling in Options validation
|
|
268
|
+
def test_options_invalid_bump_option():
|
|
269
|
+
with pytest.raises(ValueError, match="Invalid bump option"):
|
|
270
|
+
Options(publish="invalid")
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# Target: Cover string representation
|
|
274
|
+
def test_bump_option_str():
|
|
275
|
+
assert str(BumpOption.patch) == "patch"
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
# Target: Cover edge case in validation
|
|
279
|
+
def test_validate_empty_string():
|
|
280
|
+
result = Options.validate_bump_options("")
|
|
281
|
+
assert result == BumpOption.interactive
|
|
282
|
+
```
|
|
283
|
+
|
|
187
284
|
- **Dependency Management**
|
|
188
285
|
|
|
189
286
|
- Keep external dependencies to a minimum
|