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.

Files changed (49) hide show
  1. crackerjack-0.30.3/.crackerjack-hooks-updated +1 -0
  2. {crackerjack-0.29.0 → crackerjack-0.30.3}/CLAUDE.md +364 -17
  3. {crackerjack-0.29.0 → crackerjack-0.30.3}/PKG-INFO +2 -1
  4. {crackerjack-0.29.0 → crackerjack-0.30.3}/RULES.md +98 -1
  5. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/__main__.py +48 -2
  6. crackerjack-0.30.3/crackerjack/code_cleaner.py +980 -0
  7. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/crackerjack.py +713 -1048
  8. crackerjack-0.30.3/crackerjack/dynamic_config.py +586 -0
  9. {crackerjack-0.29.0 → crackerjack-0.30.3/crackerjack}/pyproject.toml +2 -1
  10. {crackerjack-0.29.0/crackerjack → crackerjack-0.30.3}/pyproject.toml +2 -1
  11. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_crackerjack.py +185 -62
  12. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_crackerjack_runner.py +9 -1
  13. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_structured_errors.py +5 -0
  14. {crackerjack-0.29.0 → crackerjack-0.30.3}/uv.lock +46 -4
  15. crackerjack-0.29.0/.pre-commit-config-ai.yaml +0 -149
  16. crackerjack-0.29.0/.pre-commit-config-fast.yaml +0 -69
  17. crackerjack-0.29.0/.pre-commit-config.yaml +0 -114
  18. crackerjack-0.29.0/crackerjack/.pre-commit-config-ai.yaml +0 -149
  19. crackerjack-0.29.0/crackerjack/.pre-commit-config-fast.yaml +0 -69
  20. crackerjack-0.29.0/crackerjack/.pre-commit-config.yaml +0 -114
  21. {crackerjack-0.29.0 → crackerjack-0.30.3}/.envrc +0 -0
  22. {crackerjack-0.29.0 → crackerjack-0.30.3}/.github/FUNDING.yml +0 -0
  23. {crackerjack-0.29.0 → crackerjack-0.30.3}/.gitignore +0 -0
  24. {crackerjack-0.29.0 → crackerjack-0.30.3}/.libcst.codemod.yaml +0 -0
  25. {crackerjack-0.29.0 → crackerjack-0.30.3}/LICENSE +0 -0
  26. {crackerjack-0.29.0 → crackerjack-0.30.3}/README-AI-AGENT.md +0 -0
  27. {crackerjack-0.29.0 → crackerjack-0.30.3}/README.md +0 -0
  28. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/.gitignore +0 -0
  29. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/.libcst.codemod.yaml +0 -0
  30. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/.pdm.toml +0 -0
  31. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/__init__.py +0 -0
  32. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/errors.py +0 -0
  33. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/interactive.py +0 -0
  34. {crackerjack-0.29.0 → crackerjack-0.30.3}/crackerjack/py313.py +0 -0
  35. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/TESTING.md +0 -0
  36. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/__init__.py +0 -0
  37. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/conftest.py +0 -0
  38. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/data/comments_sample.txt +0 -0
  39. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/data/docstrings_sample.txt +0 -0
  40. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/data/expected_comments_sample.txt +0 -0
  41. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/data/init.py +0 -0
  42. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_errors.py +0 -0
  43. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_interactive.py +0 -0
  44. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_interactive_run.py +0 -0
  45. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_main.py +0 -0
  46. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_multiline_functions.py +0 -0
  47. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_py313_advanced.py +0 -0
  48. {crackerjack-0.29.0 → crackerjack-0.30.3}/tests/test_py313_features.py +0 -0
  49. {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**: Responsible for cleaning code
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 single-file architecture for simplicity and maintainability:
424
+ Crackerjack follows a modular architecture with clear separation of concerns:
373
425
 
374
426
  ### File Structure
375
427
 
376
- - `crackerjack.py` - Main module (~3000 lines) containing all core functionality
377
- - `errors.py` - Structured error handling system
378
- - `interactive.py` - Rich-based interactive UI implementation
379
- - `py313.py` - Python 3.13+ specific feature detection
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
- - **Single-file Design**: Most functionality concentrated in `crackerjack.py` for easier maintenance
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 \<20
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
- **📦 Pre-push Hooks:**
1644
+ **📦 Manual Hook Execution:**
1301
1645
 
1302
- - Expensive operations automatically moved to pre-push stage
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
- - Install: `pre-commit install --hook-type pre-push`
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.29.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
- - Implement pytest for testing with timeout handling
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