crackerjack 0.37.9__py3-none-any.whl → 0.45.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crackerjack/README.md +19 -0
- crackerjack/__init__.py +30 -1
- crackerjack/__main__.py +342 -1263
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +27 -5
- crackerjack/adapters/_output_paths.py +167 -0
- crackerjack/adapters/_qa_adapter_base.py +309 -0
- crackerjack/adapters/_tool_adapter_base.py +706 -0
- crackerjack/adapters/ai/README.md +65 -0
- crackerjack/adapters/ai/__init__.py +5 -0
- crackerjack/adapters/ai/claude.py +853 -0
- crackerjack/adapters/complexity/README.md +53 -0
- crackerjack/adapters/complexity/__init__.py +10 -0
- crackerjack/adapters/complexity/complexipy.py +641 -0
- crackerjack/adapters/dependency/__init__.py +22 -0
- crackerjack/adapters/dependency/pip_audit.py +418 -0
- crackerjack/adapters/format/README.md +72 -0
- crackerjack/adapters/format/__init__.py +11 -0
- crackerjack/adapters/format/mdformat.py +313 -0
- crackerjack/adapters/format/ruff.py +516 -0
- crackerjack/adapters/lint/README.md +47 -0
- crackerjack/adapters/lint/__init__.py +11 -0
- crackerjack/adapters/lint/codespell.py +273 -0
- crackerjack/adapters/lsp/README.md +49 -0
- crackerjack/adapters/lsp/__init__.py +27 -0
- crackerjack/adapters/{rust_tool_manager.py → lsp/_manager.py} +3 -3
- crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
- crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
- crackerjack/adapters/refactor/README.md +59 -0
- crackerjack/adapters/refactor/__init__.py +12 -0
- crackerjack/adapters/refactor/creosote.py +318 -0
- crackerjack/adapters/refactor/refurb.py +406 -0
- crackerjack/adapters/refactor/skylos.py +494 -0
- crackerjack/adapters/sast/README.md +132 -0
- crackerjack/adapters/sast/__init__.py +32 -0
- crackerjack/adapters/sast/_base.py +201 -0
- crackerjack/adapters/sast/bandit.py +423 -0
- crackerjack/adapters/sast/pyscn.py +405 -0
- crackerjack/adapters/sast/semgrep.py +241 -0
- crackerjack/adapters/security/README.md +111 -0
- crackerjack/adapters/security/__init__.py +17 -0
- crackerjack/adapters/security/gitleaks.py +339 -0
- crackerjack/adapters/type/README.md +52 -0
- crackerjack/adapters/type/__init__.py +12 -0
- crackerjack/adapters/type/pyrefly.py +402 -0
- crackerjack/adapters/type/ty.py +402 -0
- crackerjack/adapters/type/zuban.py +522 -0
- crackerjack/adapters/utility/README.md +51 -0
- crackerjack/adapters/utility/__init__.py +10 -0
- crackerjack/adapters/utility/checks.py +884 -0
- crackerjack/agents/README.md +264 -0
- crackerjack/agents/__init__.py +40 -12
- crackerjack/agents/base.py +1 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +49 -53
- crackerjack/agents/dry_agent.py +187 -3
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/error_middleware.py +53 -0
- crackerjack/agents/formatting_agent.py +6 -8
- crackerjack/agents/helpers/__init__.py +9 -0
- crackerjack/agents/helpers/performance/__init__.py +22 -0
- crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
- crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
- crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
- crackerjack/agents/helpers/refactoring/__init__.py +22 -0
- crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
- crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
- crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
- crackerjack/agents/helpers/test_creation/__init__.py +19 -0
- crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
- crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
- crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
- crackerjack/agents/performance_agent.py +121 -1152
- crackerjack/agents/refactoring_agent.py +156 -655
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +19 -1605
- crackerjack/api.py +5 -7
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +1 -1
- crackerjack/cli/cache_handlers.py +23 -18
- crackerjack/cli/cache_handlers_enhanced.py +1 -4
- crackerjack/cli/facade.py +70 -8
- crackerjack/cli/formatting.py +13 -0
- crackerjack/cli/handlers/__init__.py +85 -0
- crackerjack/cli/handlers/advanced.py +103 -0
- crackerjack/cli/handlers/ai_features.py +62 -0
- crackerjack/cli/handlers/analytics.py +479 -0
- crackerjack/cli/handlers/changelog.py +271 -0
- crackerjack/cli/handlers/config_handlers.py +16 -0
- crackerjack/cli/handlers/coverage.py +84 -0
- crackerjack/cli/handlers/documentation.py +280 -0
- crackerjack/cli/handlers/main_handlers.py +497 -0
- crackerjack/cli/handlers/monitoring.py +371 -0
- crackerjack/cli/handlers.py +249 -49
- crackerjack/cli/interactive.py +8 -5
- crackerjack/cli/options.py +203 -110
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +60 -24
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +256 -0
- crackerjack/config/global_lock_config.py +191 -54
- crackerjack/config/hooks.py +188 -16
- crackerjack/config/loader.py +239 -0
- crackerjack/config/settings.py +141 -0
- crackerjack/config/tool_commands.py +331 -0
- crackerjack/core/README.md +393 -0
- crackerjack/core/async_workflow_orchestrator.py +79 -53
- crackerjack/core/autofix_coordinator.py +22 -9
- crackerjack/core/container.py +10 -9
- crackerjack/core/enhanced_container.py +9 -9
- crackerjack/core/performance.py +1 -1
- crackerjack/core/performance_monitor.py +5 -3
- crackerjack/core/phase_coordinator.py +1018 -634
- crackerjack/core/proactive_workflow.py +3 -3
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +167 -23
- crackerjack/core/session_coordinator.py +187 -382
- crackerjack/core/timeout_manager.py +161 -44
- crackerjack/core/workflow/__init__.py +21 -0
- crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
- crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
- crackerjack/core/workflow/workflow_issue_parser.py +714 -0
- crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
- crackerjack/core/workflow/workflow_security_gates.py +400 -0
- crackerjack/core/workflow_orchestrator.py +1247 -953
- crackerjack/data/README.md +11 -0
- crackerjack/data/__init__.py +8 -0
- crackerjack/data/models.py +79 -0
- crackerjack/data/repository.py +210 -0
- crackerjack/decorators/README.md +180 -0
- crackerjack/decorators/__init__.py +35 -0
- crackerjack/decorators/error_handling.py +649 -0
- crackerjack/decorators/error_handling_decorators.py +334 -0
- crackerjack/decorators/helpers.py +58 -0
- crackerjack/decorators/patterns.py +281 -0
- crackerjack/decorators/utils.py +58 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/ai_templates.py +1 -1
- crackerjack/documentation/dual_output_generator.py +11 -9
- crackerjack/documentation/reference_generator.py +104 -59
- crackerjack/dynamic_config.py +52 -61
- crackerjack/errors.py +1 -1
- crackerjack/events/README.md +11 -0
- crackerjack/events/__init__.py +16 -0
- crackerjack/events/telemetry.py +175 -0
- crackerjack/events/workflow_bus.py +346 -0
- crackerjack/exceptions/README.md +301 -0
- crackerjack/exceptions/__init__.py +5 -0
- crackerjack/exceptions/config.py +4 -0
- crackerjack/exceptions/tool_execution_error.py +245 -0
- crackerjack/executors/README.md +591 -0
- crackerjack/executors/__init__.py +2 -0
- crackerjack/executors/async_hook_executor.py +539 -77
- crackerjack/executors/cached_hook_executor.py +3 -3
- crackerjack/executors/hook_executor.py +967 -102
- crackerjack/executors/hook_lock_manager.py +31 -22
- crackerjack/executors/individual_hook_executor.py +66 -32
- crackerjack/executors/lsp_aware_hook_executor.py +136 -57
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +23 -7
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +8 -9
- crackerjack/intelligence/README.md +557 -0
- crackerjack/interactive.py +37 -10
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/async_hook_manager.py +41 -57
- crackerjack/managers/hook_manager.py +449 -79
- crackerjack/managers/publish_manager.py +81 -36
- crackerjack/managers/test_command_builder.py +290 -12
- crackerjack/managers/test_executor.py +93 -8
- crackerjack/managers/test_manager.py +1082 -75
- crackerjack/managers/test_progress.py +118 -26
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/cache.py +25 -2
- crackerjack/mcp/client_runner.py +35 -18
- crackerjack/mcp/context.py +9 -9
- crackerjack/mcp/dashboard.py +24 -8
- crackerjack/mcp/enhanced_progress_monitor.py +34 -23
- crackerjack/mcp/file_monitor.py +27 -6
- crackerjack/mcp/progress_components.py +45 -34
- crackerjack/mcp/progress_monitor.py +6 -9
- crackerjack/mcp/rate_limiter.py +11 -7
- crackerjack/mcp/server.py +2 -0
- crackerjack/mcp/server_core.py +187 -55
- crackerjack/mcp/service_watchdog.py +12 -9
- crackerjack/mcp/task_manager.py +2 -2
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +2 -0
- crackerjack/mcp/tools/core_tools.py +75 -52
- crackerjack/mcp/tools/execution_tools.py +87 -31
- crackerjack/mcp/tools/intelligence_tools.py +2 -2
- crackerjack/mcp/tools/proactive_tools.py +1 -1
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +180 -132
- crackerjack/mcp/tools/workflow_executor.py +87 -46
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/app.py +11 -1
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +27 -4
- crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
- crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
- crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
- crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
- crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
- crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
- crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
- crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
- crackerjack/mcp/websocket/monitoring/factory.py +109 -0
- crackerjack/mcp/websocket/monitoring/filters.py +10 -0
- crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
- crackerjack/mcp/websocket/monitoring/models.py +90 -0
- crackerjack/mcp/websocket/monitoring/utils.py +171 -0
- crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
- crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
- crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
- crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
- crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
- crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
- crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
- crackerjack/mcp/websocket/server.py +1 -3
- crackerjack/mcp/websocket/websocket_handler.py +107 -6
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +10 -1
- crackerjack/models/config.py +639 -22
- crackerjack/models/config_adapter.py +6 -6
- crackerjack/models/protocols.py +1167 -23
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +19 -3
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/ai_agent_watchdog.py +5 -4
- crackerjack/monitoring/metrics_collector.py +4 -3
- crackerjack/monitoring/regression_prevention.py +4 -3
- crackerjack/monitoring/websocket_server.py +4 -241
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +20 -67
- crackerjack/orchestration/cache/README.md +312 -0
- crackerjack/orchestration/cache/__init__.py +37 -0
- crackerjack/orchestration/cache/memory_cache.py +338 -0
- crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
- crackerjack/orchestration/config.py +297 -0
- crackerjack/orchestration/coverage_improvement.py +13 -6
- crackerjack/orchestration/execution_strategies.py +6 -6
- crackerjack/orchestration/hook_orchestrator.py +1398 -0
- crackerjack/orchestration/strategies/README.md +401 -0
- crackerjack/orchestration/strategies/__init__.py +39 -0
- crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
- crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
- crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
- crackerjack/orchestration/test_progress_streamer.py +1 -1
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/hooks.py +3 -2
- crackerjack/plugins/loader.py +3 -3
- crackerjack/plugins/managers.py +1 -1
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +8 -21
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
- crackerjack/services/ai/embeddings.py +444 -0
- crackerjack/services/ai/intelligent_commit.py +328 -0
- crackerjack/services/ai/predictive_analytics.py +510 -0
- crackerjack/services/api_extractor.py +5 -3
- crackerjack/services/bounded_status_operations.py +45 -5
- crackerjack/services/cache.py +249 -318
- crackerjack/services/changelog_automation.py +7 -3
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +83 -39
- crackerjack/services/config_merge.py +9 -6
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +13 -26
- crackerjack/services/coverage_badge_service.py +6 -4
- crackerjack/services/coverage_ratchet.py +53 -27
- crackerjack/services/debug.py +18 -7
- crackerjack/services/dependency_analyzer.py +4 -4
- crackerjack/services/dependency_monitor.py +13 -13
- crackerjack/services/documentation_generator.py +4 -2
- crackerjack/services/documentation_service.py +62 -33
- crackerjack/services/enhanced_filesystem.py +81 -27
- crackerjack/services/enterprise_optimizer.py +1 -1
- crackerjack/services/error_pattern_analyzer.py +10 -10
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +5 -7
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +80 -109
- crackerjack/services/git.py +99 -5
- crackerjack/services/health_metrics.py +4 -6
- crackerjack/services/heatmap_generator.py +12 -3
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +101 -49
- crackerjack/services/log_manager.py +2 -2
- crackerjack/services/logging.py +120 -68
- crackerjack/services/lsp_client.py +12 -12
- crackerjack/services/memory_optimizer.py +27 -22
- crackerjack/services/monitoring/README.md +30 -0
- crackerjack/services/monitoring/__init__.py +9 -0
- crackerjack/services/monitoring/dependency_monitor.py +678 -0
- crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
- crackerjack/services/monitoring/health_metrics.py +716 -0
- crackerjack/services/monitoring/metrics.py +587 -0
- crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
- crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
- crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
- crackerjack/services/parallel_executor.py +166 -55
- crackerjack/services/patterns/__init__.py +142 -0
- crackerjack/services/patterns/agents.py +107 -0
- crackerjack/services/patterns/code/__init__.py +15 -0
- crackerjack/services/patterns/code/detection.py +118 -0
- crackerjack/services/patterns/code/imports.py +107 -0
- crackerjack/services/patterns/code/paths.py +159 -0
- crackerjack/services/patterns/code/performance.py +119 -0
- crackerjack/services/patterns/code/replacement.py +36 -0
- crackerjack/services/patterns/core.py +212 -0
- crackerjack/services/patterns/documentation/__init__.py +14 -0
- crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
- crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
- crackerjack/services/patterns/documentation/docstrings.py +89 -0
- crackerjack/services/patterns/formatting.py +226 -0
- crackerjack/services/patterns/operations.py +339 -0
- crackerjack/services/patterns/security/__init__.py +23 -0
- crackerjack/services/patterns/security/code_injection.py +122 -0
- crackerjack/services/patterns/security/credentials.py +190 -0
- crackerjack/services/patterns/security/path_traversal.py +221 -0
- crackerjack/services/patterns/security/unsafe_operations.py +216 -0
- crackerjack/services/patterns/templates.py +62 -0
- crackerjack/services/patterns/testing/__init__.py +18 -0
- crackerjack/services/patterns/testing/error_patterns.py +107 -0
- crackerjack/services/patterns/testing/pytest_output.py +126 -0
- crackerjack/services/patterns/tool_output/__init__.py +16 -0
- crackerjack/services/patterns/tool_output/bandit.py +72 -0
- crackerjack/services/patterns/tool_output/other.py +97 -0
- crackerjack/services/patterns/tool_output/pyright.py +67 -0
- crackerjack/services/patterns/tool_output/ruff.py +44 -0
- crackerjack/services/patterns/url_sanitization.py +114 -0
- crackerjack/services/patterns/utilities.py +42 -0
- crackerjack/services/patterns/utils.py +339 -0
- crackerjack/services/patterns/validation.py +46 -0
- crackerjack/services/patterns/versioning.py +62 -0
- crackerjack/services/predictive_analytics.py +21 -8
- crackerjack/services/profiler.py +280 -0
- crackerjack/services/quality/README.md +415 -0
- crackerjack/services/quality/__init__.py +11 -0
- crackerjack/services/quality/anomaly_detector.py +392 -0
- crackerjack/services/quality/pattern_cache.py +333 -0
- crackerjack/services/quality/pattern_detector.py +479 -0
- crackerjack/services/quality/qa_orchestrator.py +491 -0
- crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
- crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
- crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
- crackerjack/services/regex_patterns.py +58 -2987
- crackerjack/services/regex_utils.py +55 -29
- crackerjack/services/secure_status_formatter.py +42 -15
- crackerjack/services/secure_subprocess.py +35 -2
- crackerjack/services/security.py +16 -8
- crackerjack/services/server_manager.py +40 -51
- crackerjack/services/smart_scheduling.py +46 -6
- crackerjack/services/status_authentication.py +3 -3
- crackerjack/services/thread_safe_status_collector.py +1 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +9 -5
- crackerjack/services/unified_config.py +43 -351
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +6 -4
- crackerjack/services/version_checker.py +14 -8
- crackerjack/services/zuban_lsp_service.py +5 -4
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/init.md +2 -12
- crackerjack/slash_commands/run.md +84 -50
- crackerjack/tools/README.md +11 -0
- crackerjack/tools/__init__.py +30 -0
- crackerjack/tools/_git_utils.py +105 -0
- crackerjack/tools/check_added_large_files.py +139 -0
- crackerjack/tools/check_ast.py +105 -0
- crackerjack/tools/check_json.py +103 -0
- crackerjack/tools/check_jsonschema.py +297 -0
- crackerjack/tools/check_toml.py +103 -0
- crackerjack/tools/check_yaml.py +110 -0
- crackerjack/tools/codespell_wrapper.py +72 -0
- crackerjack/tools/end_of_file_fixer.py +202 -0
- crackerjack/tools/format_json.py +128 -0
- crackerjack/tools/mdformat_wrapper.py +114 -0
- crackerjack/tools/trailing_whitespace.py +198 -0
- crackerjack/tools/validate_regex_patterns.py +7 -3
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/dashboard_renderer.py +28 -0
- crackerjack/ui/templates/README.md +11 -0
- crackerjack/utils/console_utils.py +13 -0
- crackerjack/utils/dependency_guard.py +230 -0
- crackerjack/utils/retry_utils.py +275 -0
- crackerjack/workflows/README.md +590 -0
- crackerjack/workflows/__init__.py +46 -0
- crackerjack/workflows/actions.py +811 -0
- crackerjack/workflows/auto_fix.py +444 -0
- crackerjack/workflows/container_builder.py +499 -0
- crackerjack/workflows/definitions.py +443 -0
- crackerjack/workflows/engine.py +177 -0
- crackerjack/workflows/event_bridge.py +242 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack/managers/test_manager_backup.py +0 -1075
- crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
- crackerjack/mixins/__init__.py +0 -3
- crackerjack/mixins/error_handling.py +0 -145
- crackerjack/services/config.py +0 -358
- crackerjack/ui/server_panels.py +0 -125
- crackerjack-0.37.9.dist-info/RECORD +0 -231
- /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
- /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"""Reusable decorators for consistent error handling across the codebase."""
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
import json
|
|
5
|
+
import subprocess
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from loguru import logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def handle_file_errors(
|
|
13
|
+
exceptions: tuple[type[Exception], ...] = (
|
|
14
|
+
OSError,
|
|
15
|
+
FileNotFoundError,
|
|
16
|
+
PermissionError,
|
|
17
|
+
),
|
|
18
|
+
default_return: Any = None,
|
|
19
|
+
log_error: bool = True,
|
|
20
|
+
reraise: bool
|
|
21
|
+
| None = None, # If None, reraise is False when default_return is provided
|
|
22
|
+
):
|
|
23
|
+
"""
|
|
24
|
+
Decorator to handle common file operation errors consistently.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
exceptions: Tuple of exception types to catch
|
|
28
|
+
default_return: Value to return when an exception occurs
|
|
29
|
+
log_error: Whether to log the error
|
|
30
|
+
reraise: Whether to reraise the exception after handling (None means False if default_return is provided)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def decorator(func: Callable) -> Callable:
|
|
34
|
+
@functools.wraps(func)
|
|
35
|
+
def wrapper(*args, **kwargs):
|
|
36
|
+
try:
|
|
37
|
+
return func(*args, **kwargs)
|
|
38
|
+
except exceptions as e:
|
|
39
|
+
if log_error:
|
|
40
|
+
logger.error(f"File operation failed in {func.__name__}: {e}")
|
|
41
|
+
# Determine if we should reraise:
|
|
42
|
+
# - if reraise is explicitly set to True/False, respect that
|
|
43
|
+
# - if reraise is None (default):
|
|
44
|
+
# - reraise if no default_return is provided (when default_return is None)
|
|
45
|
+
# - don't reraise if default_return is provided
|
|
46
|
+
should_reraise = (
|
|
47
|
+
reraise if reraise is not None else (default_return is None)
|
|
48
|
+
)
|
|
49
|
+
if should_reraise:
|
|
50
|
+
raise
|
|
51
|
+
return default_return
|
|
52
|
+
|
|
53
|
+
return wrapper
|
|
54
|
+
|
|
55
|
+
return decorator
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def handle_json_errors(
|
|
59
|
+
exceptions: tuple[type[Exception], ...] = (
|
|
60
|
+
json.JSONDecodeError,
|
|
61
|
+
TypeError,
|
|
62
|
+
ValueError,
|
|
63
|
+
),
|
|
64
|
+
default_return: Any = None,
|
|
65
|
+
log_error: bool = True,
|
|
66
|
+
reraise: bool
|
|
67
|
+
| None = None, # If None, reraise is False when default_return is provided
|
|
68
|
+
):
|
|
69
|
+
"""
|
|
70
|
+
Decorator to handle JSON parsing errors consistently.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
exceptions: Tuple of exception types to catch
|
|
74
|
+
default_return: Value to return when an exception occurs
|
|
75
|
+
log_error: Whether to log the error
|
|
76
|
+
reraise: Whether to reraise the exception after handling (None means False if default_return is provided)
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def decorator(func: Callable) -> Callable:
|
|
80
|
+
@functools.wraps(func)
|
|
81
|
+
def wrapper(*args, **kwargs):
|
|
82
|
+
try:
|
|
83
|
+
result = func(*args, **kwargs)
|
|
84
|
+
return result
|
|
85
|
+
except exceptions as e:
|
|
86
|
+
if log_error:
|
|
87
|
+
logger.error(f"JSON operation failed in {func.__name__}: {e}")
|
|
88
|
+
# Determine if we should reraise:
|
|
89
|
+
# - if reraise is explicitly set to True/False, respect that
|
|
90
|
+
# - if reraise is None (default):
|
|
91
|
+
# - reraise if no default_return is provided (when default_return is None)
|
|
92
|
+
# - don't reraise if default_return is provided
|
|
93
|
+
should_reraise = (
|
|
94
|
+
reraise if reraise is not None else (default_return is None)
|
|
95
|
+
)
|
|
96
|
+
if should_reraise:
|
|
97
|
+
raise
|
|
98
|
+
return default_return
|
|
99
|
+
|
|
100
|
+
return wrapper
|
|
101
|
+
|
|
102
|
+
return decorator
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def handle_subprocess_errors(
|
|
106
|
+
exceptions: tuple[type[Exception], ...] = (
|
|
107
|
+
subprocess.CalledProcessError,
|
|
108
|
+
subprocess.TimeoutExpired,
|
|
109
|
+
),
|
|
110
|
+
default_return: Any = None,
|
|
111
|
+
log_error: bool = True,
|
|
112
|
+
reraise: bool
|
|
113
|
+
| None = None, # If None, reraise is False when default_return is provided
|
|
114
|
+
):
|
|
115
|
+
"""
|
|
116
|
+
Decorator to handle subprocess execution errors consistently.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
exceptions: Tuple of exception types to catch
|
|
120
|
+
default_return: Value to return when an exception occurs
|
|
121
|
+
log_error: Whether to log the error
|
|
122
|
+
reraise: Whether to reraise the exception after handling (None means False if default_return is provided)
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def decorator(func: Callable) -> Callable:
|
|
126
|
+
@functools.wraps(func)
|
|
127
|
+
def wrapper(*args, **kwargs):
|
|
128
|
+
try:
|
|
129
|
+
result = func(*args, **kwargs)
|
|
130
|
+
return result
|
|
131
|
+
except exceptions as e:
|
|
132
|
+
if log_error:
|
|
133
|
+
logger.error(f"Subprocess operation failed in {func.__name__}: {e}")
|
|
134
|
+
# Determine if we should reraise:
|
|
135
|
+
# - if reraise is explicitly set to True/False, respect that
|
|
136
|
+
# - if reraise is None (default):
|
|
137
|
+
# - reraise if no default_return is provided (when default_return is None)
|
|
138
|
+
# - don't reraise if default_return is provided
|
|
139
|
+
should_reraise = (
|
|
140
|
+
reraise if reraise is not None else (default_return is None)
|
|
141
|
+
)
|
|
142
|
+
if should_reraise:
|
|
143
|
+
raise
|
|
144
|
+
return default_return
|
|
145
|
+
|
|
146
|
+
return wrapper
|
|
147
|
+
|
|
148
|
+
return decorator
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def handle_validation_errors(
|
|
152
|
+
exceptions: tuple[type[Exception], ...] = (ValueError, TypeError, AttributeError),
|
|
153
|
+
default_return: Any = None,
|
|
154
|
+
log_error: bool = True,
|
|
155
|
+
reraise: bool
|
|
156
|
+
| None = None, # If None, reraise is False when default_return is provided
|
|
157
|
+
):
|
|
158
|
+
"""
|
|
159
|
+
Decorator to handle data validation errors consistently.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
exceptions: Tuple of exception types to catch
|
|
163
|
+
default_return: Value to return when an exception occurs
|
|
164
|
+
log_error: Whether to log the error
|
|
165
|
+
reraise: Whether to reraise the exception after handling (None means False if default_return is provided)
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def decorator(func: Callable) -> Callable:
|
|
169
|
+
@functools.wraps(func)
|
|
170
|
+
def wrapper(*args, **kwargs):
|
|
171
|
+
try:
|
|
172
|
+
result = func(*args, **kwargs)
|
|
173
|
+
return result
|
|
174
|
+
except exceptions as e:
|
|
175
|
+
if log_error:
|
|
176
|
+
logger.error(f"Validation failed in {func.__name__}: {e}")
|
|
177
|
+
# Determine if we should reraise:
|
|
178
|
+
# - if reraise is explicitly set to True/False, respect that
|
|
179
|
+
# - if reraise is None (default):
|
|
180
|
+
# - reraise if no default_return is provided (when default_return is None)
|
|
181
|
+
# - don't reraise if default_return is provided
|
|
182
|
+
should_reraise = (
|
|
183
|
+
reraise if reraise is not None else (default_return is None)
|
|
184
|
+
)
|
|
185
|
+
if should_reraise:
|
|
186
|
+
raise
|
|
187
|
+
return default_return
|
|
188
|
+
|
|
189
|
+
return wrapper
|
|
190
|
+
|
|
191
|
+
return decorator
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def handle_network_errors(
|
|
195
|
+
exceptions: tuple[type[Exception], ...] = (
|
|
196
|
+
ConnectionError,
|
|
197
|
+
ConnectionRefusedError,
|
|
198
|
+
TimeoutError,
|
|
199
|
+
# Add more common network errors as needed
|
|
200
|
+
),
|
|
201
|
+
default_return: Any = None,
|
|
202
|
+
log_error: bool = True,
|
|
203
|
+
reraise: bool
|
|
204
|
+
| None = None, # If None, reraise is False when default_return is provided
|
|
205
|
+
):
|
|
206
|
+
"""
|
|
207
|
+
Decorator to handle network-related errors consistently.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
exceptions: Tuple of exception types to catch
|
|
211
|
+
default_return: Value to return when an exception occurs
|
|
212
|
+
log_error: Whether to log the error
|
|
213
|
+
reraise: Whether to reraise the exception after handling (None means False if default_return is provided)
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
def decorator(func: Callable) -> Callable:
|
|
217
|
+
@functools.wraps(func)
|
|
218
|
+
def wrapper(*args, **kwargs):
|
|
219
|
+
try:
|
|
220
|
+
result = func(*args, **kwargs)
|
|
221
|
+
return result
|
|
222
|
+
except exceptions as e:
|
|
223
|
+
if log_error:
|
|
224
|
+
logger.error(f"Network operation failed in {func.__name__}: {e}")
|
|
225
|
+
# Determine if we should reraise:
|
|
226
|
+
# - if reraise is explicitly set to True/False, respect that
|
|
227
|
+
# - if reraise is None (default):
|
|
228
|
+
# - reraise if no default_return is provided (when default_return is None)
|
|
229
|
+
# - don't reraise if default_return is provided
|
|
230
|
+
should_reraise = (
|
|
231
|
+
reraise if reraise is not None else (default_return is None)
|
|
232
|
+
)
|
|
233
|
+
if should_reraise:
|
|
234
|
+
raise
|
|
235
|
+
return default_return
|
|
236
|
+
|
|
237
|
+
return wrapper
|
|
238
|
+
|
|
239
|
+
return decorator
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def handle_all_errors(
|
|
243
|
+
log_error: bool = True,
|
|
244
|
+
reraise: bool
|
|
245
|
+
| None = None, # If None, reraise is False when default_return is provided
|
|
246
|
+
default_return: Any = None,
|
|
247
|
+
exclude: tuple[type[BaseException], ...] = (KeyboardInterrupt, SystemExit),
|
|
248
|
+
):
|
|
249
|
+
"""
|
|
250
|
+
Decorator to handle all errors except for specific system exceptions.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
log_error: Whether to log the error
|
|
254
|
+
reraise: Whether to reraise the exception after handling (None means False if default_return is provided)
|
|
255
|
+
default_return: Value to return when an exception occurs
|
|
256
|
+
exclude: Tuple of exception types to exclude from handling
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
def decorator(func: Callable) -> Callable:
|
|
260
|
+
@functools.wraps(func)
|
|
261
|
+
def wrapper(*args, **kwargs):
|
|
262
|
+
try:
|
|
263
|
+
return func(*args, **kwargs)
|
|
264
|
+
except exclude:
|
|
265
|
+
# Don't handle system exceptions like KeyboardInterrupt
|
|
266
|
+
raise
|
|
267
|
+
except Exception as e:
|
|
268
|
+
if log_error:
|
|
269
|
+
logger.error(f"Unexpected error in {func.__name__}: {e}")
|
|
270
|
+
# Determine if we should reraise:
|
|
271
|
+
# - if reraise is explicitly set to True/False, respect that
|
|
272
|
+
# - if reraise is None (default):
|
|
273
|
+
# - reraise if no default_return is provided (when default_return is None)
|
|
274
|
+
# - don't reraise if default_return is provided
|
|
275
|
+
should_reraise = (
|
|
276
|
+
reraise if reraise is not None else (default_return is None)
|
|
277
|
+
)
|
|
278
|
+
if should_reraise:
|
|
279
|
+
raise
|
|
280
|
+
return default_return
|
|
281
|
+
|
|
282
|
+
return wrapper
|
|
283
|
+
|
|
284
|
+
return decorator
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def retry_on_error(
|
|
288
|
+
max_attempts: int = 3,
|
|
289
|
+
delay: float = 1.0,
|
|
290
|
+
backoff: float = 2.0,
|
|
291
|
+
exceptions: tuple[type[Exception], ...] = (Exception,),
|
|
292
|
+
log_retry: bool = True,
|
|
293
|
+
):
|
|
294
|
+
"""
|
|
295
|
+
Decorator to retry a function on specific exceptions.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
max_attempts: Maximum number of attempts
|
|
299
|
+
delay: Initial delay between attempts (in seconds)
|
|
300
|
+
backoff: Multiplier for delay after each attempt
|
|
301
|
+
exceptions: Tuple of exception types to retry on
|
|
302
|
+
log_retry: Whether to log retry attempts
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
def decorator(func: Callable) -> Callable:
|
|
306
|
+
@functools.wraps(func)
|
|
307
|
+
def wrapper(*args, **kwargs):
|
|
308
|
+
current_delay = delay
|
|
309
|
+
last_exception = None
|
|
310
|
+
|
|
311
|
+
for attempt in range(max_attempts):
|
|
312
|
+
try:
|
|
313
|
+
return func(*args, **kwargs)
|
|
314
|
+
except exceptions as e:
|
|
315
|
+
last_exception = e
|
|
316
|
+
if log_retry:
|
|
317
|
+
logger.warning(
|
|
318
|
+
f"Attempt {attempt + 1}/{max_attempts} failed in {func.__name__}: {e}. "
|
|
319
|
+
f"Retrying in {current_delay}s..."
|
|
320
|
+
)
|
|
321
|
+
if attempt < max_attempts - 1: # Don't sleep after the last attempt
|
|
322
|
+
import time
|
|
323
|
+
|
|
324
|
+
time.sleep(current_delay)
|
|
325
|
+
current_delay *= backoff
|
|
326
|
+
|
|
327
|
+
logger.error(
|
|
328
|
+
f"All {max_attempts} attempts failed in {func.__name__}: {last_exception}"
|
|
329
|
+
)
|
|
330
|
+
raise last_exception
|
|
331
|
+
|
|
332
|
+
return wrapper
|
|
333
|
+
|
|
334
|
+
return decorator
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Shared utilities for error handling decorators."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import inspect
|
|
5
|
+
import typing as t
|
|
6
|
+
from functools import wraps
|
|
7
|
+
|
|
8
|
+
F = t.TypeVar("F", bound=t.Callable[..., t.Any])
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def is_async_function(func: t.Callable[..., t.Any]) -> bool:
|
|
12
|
+
"""Check if a function is async."""
|
|
13
|
+
return asyncio.iscoroutinefunction(func)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def preserve_signature[F: t.Callable[..., t.Any]](
|
|
17
|
+
wrapper: F,
|
|
18
|
+
) -> t.Callable[[t.Callable[..., t.Any]], F]:
|
|
19
|
+
"""Preserve function signature in decorators."""
|
|
20
|
+
|
|
21
|
+
def decorator(func: t.Callable[..., t.Any]) -> F:
|
|
22
|
+
wrapped = wraps(func)(wrapper)
|
|
23
|
+
# Preserve signature metadata
|
|
24
|
+
wrapped.__wrapped__ = func # type: ignore[attr-defined]
|
|
25
|
+
return t.cast(F, wrapped)
|
|
26
|
+
|
|
27
|
+
return decorator
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_function_context(func: t.Callable[..., t.Any]) -> dict[str, t.Any]:
|
|
31
|
+
"""Extract context information from a function for error reporting."""
|
|
32
|
+
return {
|
|
33
|
+
"function_name": func.__name__,
|
|
34
|
+
"module": func.__module__,
|
|
35
|
+
"qualname": func.__qualname__,
|
|
36
|
+
"is_async": is_async_function(func),
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def format_exception_chain(exc: BaseException) -> list[str]:
|
|
41
|
+
"""Format exception chain for logging."""
|
|
42
|
+
chain: list[str] = []
|
|
43
|
+
current: BaseException | None = exc
|
|
44
|
+
|
|
45
|
+
while current is not None:
|
|
46
|
+
chain.append(f"{type(current).__name__}: {current}")
|
|
47
|
+
current = current.__cause__ or current.__context__
|
|
48
|
+
|
|
49
|
+
return chain
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_callable_params(func: t.Callable[..., t.Any]) -> list[inspect.Parameter]:
|
|
53
|
+
"""Get function parameters using inspect."""
|
|
54
|
+
try:
|
|
55
|
+
sig = inspect.signature(func)
|
|
56
|
+
return list(sig.parameters.values())
|
|
57
|
+
except (ValueError, TypeError):
|
|
58
|
+
return []
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"""Error pattern detection and caching decorator."""
|
|
2
|
+
|
|
3
|
+
import typing as t
|
|
4
|
+
from functools import wraps
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from ..errors import CrackerjackError
|
|
8
|
+
from ..mcp.cache import ErrorCache, ErrorPattern
|
|
9
|
+
from .helpers import get_function_context, is_async_function
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def cache_errors(
|
|
13
|
+
cache_dir: Path | None = None,
|
|
14
|
+
error_type: str | None = None,
|
|
15
|
+
auto_analyze: bool = True,
|
|
16
|
+
) -> t.Callable[[t.Callable[..., t.Any]], t.Callable[..., t.Any]]:
|
|
17
|
+
"""
|
|
18
|
+
Detect and cache error patterns for analysis and auto-fixing.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
cache_dir: Directory for error cache (default: ~/.cache/crackerjack-mcp)
|
|
22
|
+
error_type: Override error type classification (default: auto-detect)
|
|
23
|
+
auto_analyze: Automatically analyze errors for patterns (default: True)
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Decorated function with error pattern caching
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
>>> from pathlib import Path
|
|
30
|
+
>>>
|
|
31
|
+
>>> @cache_errors(error_type="lint", auto_analyze=True)
|
|
32
|
+
>>> async def run_linter(files: list[Path]) -> bool:
|
|
33
|
+
... # Errors are automatically cached and analyzed
|
|
34
|
+
... return await linter.run(files)
|
|
35
|
+
|
|
36
|
+
>>> @cache_errors()
|
|
37
|
+
>>> def execute_command(cmd: list[str]) -> bool:
|
|
38
|
+
... # Error patterns tracked for future auto-fix
|
|
39
|
+
... return subprocess.run(cmd).returncode == 0
|
|
40
|
+
|
|
41
|
+
Notes:
|
|
42
|
+
- Integrates with Crackerjack's ErrorCache system
|
|
43
|
+
- Tracks error frequency and common fixes
|
|
44
|
+
- Enables intelligent auto-fix suggestions
|
|
45
|
+
- Works with AI agents for pattern recognition
|
|
46
|
+
"""
|
|
47
|
+
error_cache = ErrorCache(cache_dir=cache_dir)
|
|
48
|
+
|
|
49
|
+
def decorator(func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
|
|
50
|
+
if is_async_function(func):
|
|
51
|
+
return _create_async_wrapper(func, error_cache, error_type, auto_analyze)
|
|
52
|
+
return _create_sync_wrapper(func, error_cache, error_type, auto_analyze)
|
|
53
|
+
|
|
54
|
+
return decorator
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _create_async_wrapper(
|
|
58
|
+
func: t.Callable[..., t.Any],
|
|
59
|
+
error_cache: ErrorCache,
|
|
60
|
+
error_type: str | None,
|
|
61
|
+
auto_analyze: bool,
|
|
62
|
+
) -> t.Callable[..., t.Any]:
|
|
63
|
+
"""Create async wrapper with error caching."""
|
|
64
|
+
|
|
65
|
+
@wraps(func)
|
|
66
|
+
async def async_wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any:
|
|
67
|
+
try:
|
|
68
|
+
result = await func(*args, **kwargs)
|
|
69
|
+
await _handle_result_analysis(
|
|
70
|
+
result, error_cache, func, error_type, auto_analyze
|
|
71
|
+
)
|
|
72
|
+
return result
|
|
73
|
+
except CrackerjackError as e:
|
|
74
|
+
await _cache_crackerjack_error(error_cache, e, func, error_type)
|
|
75
|
+
raise
|
|
76
|
+
except Exception as e:
|
|
77
|
+
await _handle_generic_exception(
|
|
78
|
+
e, error_cache, func, error_type, auto_analyze
|
|
79
|
+
)
|
|
80
|
+
raise
|
|
81
|
+
|
|
82
|
+
return async_wrapper
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _create_sync_wrapper(
|
|
86
|
+
func: t.Callable[..., t.Any],
|
|
87
|
+
error_cache: ErrorCache,
|
|
88
|
+
error_type: str | None,
|
|
89
|
+
auto_analyze: bool,
|
|
90
|
+
) -> t.Callable[..., t.Any]:
|
|
91
|
+
"""Create sync wrapper with error caching."""
|
|
92
|
+
|
|
93
|
+
@wraps(func)
|
|
94
|
+
def sync_wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any:
|
|
95
|
+
try:
|
|
96
|
+
result = func(*args, **kwargs)
|
|
97
|
+
_handle_result_analysis_sync(
|
|
98
|
+
result, error_cache, func, error_type, auto_analyze
|
|
99
|
+
)
|
|
100
|
+
return result
|
|
101
|
+
except CrackerjackError as e:
|
|
102
|
+
_cache_crackerjack_error_sync(error_cache, e, func, error_type)
|
|
103
|
+
raise
|
|
104
|
+
except Exception as e:
|
|
105
|
+
_handle_generic_exception_sync(
|
|
106
|
+
e, error_cache, func, error_type, auto_analyze
|
|
107
|
+
)
|
|
108
|
+
raise
|
|
109
|
+
|
|
110
|
+
return sync_wrapper
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
async def _handle_result_analysis(
|
|
114
|
+
result: t.Any,
|
|
115
|
+
cache: ErrorCache,
|
|
116
|
+
func: t.Callable[..., t.Any],
|
|
117
|
+
error_type: str | None,
|
|
118
|
+
auto_analyze: bool,
|
|
119
|
+
) -> None:
|
|
120
|
+
"""Handle result error analysis for async functions."""
|
|
121
|
+
if not auto_analyze or not isinstance(result, dict):
|
|
122
|
+
return
|
|
123
|
+
if "error" in result or "errors" in result:
|
|
124
|
+
await _analyze_result_errors(cache, result, func, error_type)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _handle_result_analysis_sync(
|
|
128
|
+
result: t.Any,
|
|
129
|
+
cache: ErrorCache,
|
|
130
|
+
func: t.Callable[..., t.Any],
|
|
131
|
+
error_type: str | None,
|
|
132
|
+
auto_analyze: bool,
|
|
133
|
+
) -> None:
|
|
134
|
+
"""Handle result error analysis for sync functions."""
|
|
135
|
+
if not auto_analyze or not isinstance(result, dict):
|
|
136
|
+
return
|
|
137
|
+
if "error" in result or "errors" in result:
|
|
138
|
+
_analyze_result_errors_sync(cache, result, func, error_type)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
async def _handle_generic_exception(
|
|
142
|
+
error: Exception,
|
|
143
|
+
cache: ErrorCache,
|
|
144
|
+
func: t.Callable[..., t.Any],
|
|
145
|
+
error_type: str | None,
|
|
146
|
+
auto_analyze: bool,
|
|
147
|
+
) -> None:
|
|
148
|
+
"""Handle generic exception caching for async functions."""
|
|
149
|
+
if auto_analyze:
|
|
150
|
+
await _cache_exception(cache, error, func, error_type)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _handle_generic_exception_sync(
|
|
154
|
+
error: Exception,
|
|
155
|
+
cache: ErrorCache,
|
|
156
|
+
func: t.Callable[..., t.Any],
|
|
157
|
+
error_type: str | None,
|
|
158
|
+
auto_analyze: bool,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""Handle generic exception caching for sync functions."""
|
|
161
|
+
if auto_analyze:
|
|
162
|
+
_cache_exception_sync(cache, error, func, error_type)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
async def _analyze_result_errors(
|
|
166
|
+
cache: ErrorCache,
|
|
167
|
+
result: dict[str, t.Any],
|
|
168
|
+
func: t.Callable[..., t.Any],
|
|
169
|
+
error_type_override: str | None,
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Analyze errors from result dictionary (async)."""
|
|
172
|
+
error_data = result.get("error") or result.get("errors", "")
|
|
173
|
+
if isinstance(error_data, str) and error_data:
|
|
174
|
+
context = get_function_context(func)
|
|
175
|
+
detected_type = error_type_override or context["function_name"]
|
|
176
|
+
|
|
177
|
+
pattern = cache.create_pattern_from_error(error_data, detected_type)
|
|
178
|
+
if pattern:
|
|
179
|
+
await cache.add_pattern(pattern)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _analyze_result_errors_sync(
|
|
183
|
+
cache: ErrorCache,
|
|
184
|
+
result: dict[str, t.Any],
|
|
185
|
+
func: t.Callable[..., t.Any],
|
|
186
|
+
error_type_override: str | None,
|
|
187
|
+
) -> None:
|
|
188
|
+
"""Analyze errors from result dictionary (sync)."""
|
|
189
|
+
import asyncio
|
|
190
|
+
|
|
191
|
+
error_data = result.get("error") or result.get("errors", "")
|
|
192
|
+
if isinstance(error_data, str) and error_data:
|
|
193
|
+
context = get_function_context(func)
|
|
194
|
+
detected_type = error_type_override or context["function_name"]
|
|
195
|
+
|
|
196
|
+
pattern = cache.create_pattern_from_error(error_data, detected_type)
|
|
197
|
+
if pattern:
|
|
198
|
+
# Run async method in sync context
|
|
199
|
+
asyncio.run(cache.add_pattern(pattern))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
async def _cache_crackerjack_error(
|
|
203
|
+
cache: ErrorCache,
|
|
204
|
+
error: CrackerjackError,
|
|
205
|
+
func: t.Callable[..., t.Any],
|
|
206
|
+
error_type_override: str | None,
|
|
207
|
+
) -> None:
|
|
208
|
+
"""Cache a CrackerjackError (async)."""
|
|
209
|
+
get_function_context(func)
|
|
210
|
+
detected_type = error_type_override or error.error_code.name
|
|
211
|
+
|
|
212
|
+
pattern = ErrorPattern(
|
|
213
|
+
pattern_id=f"{detected_type}_{error.error_code.value}_{hash(error.message) % 10000}",
|
|
214
|
+
error_type=detected_type,
|
|
215
|
+
error_code=str(error.error_code.value),
|
|
216
|
+
message_pattern=error.message,
|
|
217
|
+
common_fixes=[error.recovery] if error.recovery else None,
|
|
218
|
+
auto_fixable=False,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
await cache.add_pattern(pattern)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _cache_crackerjack_error_sync(
|
|
225
|
+
cache: ErrorCache,
|
|
226
|
+
error: CrackerjackError,
|
|
227
|
+
func: t.Callable[..., t.Any],
|
|
228
|
+
error_type_override: str | None,
|
|
229
|
+
) -> None:
|
|
230
|
+
"""Cache a CrackerjackError (sync)."""
|
|
231
|
+
import asyncio
|
|
232
|
+
|
|
233
|
+
get_function_context(func)
|
|
234
|
+
detected_type = error_type_override or error.error_code.name
|
|
235
|
+
|
|
236
|
+
pattern = ErrorPattern(
|
|
237
|
+
pattern_id=f"{detected_type}_{error.error_code.value}_{hash(error.message) % 10000}",
|
|
238
|
+
error_type=detected_type,
|
|
239
|
+
error_code=str(error.error_code.value),
|
|
240
|
+
message_pattern=error.message,
|
|
241
|
+
common_fixes=[error.recovery] if error.recovery else None,
|
|
242
|
+
auto_fixable=False,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
asyncio.run(cache.add_pattern(pattern))
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
async def _cache_exception(
|
|
249
|
+
cache: ErrorCache,
|
|
250
|
+
error: Exception,
|
|
251
|
+
func: t.Callable[..., t.Any],
|
|
252
|
+
error_type_override: str | None,
|
|
253
|
+
) -> None:
|
|
254
|
+
"""Cache a generic exception (async)."""
|
|
255
|
+
get_function_context(func)
|
|
256
|
+
detected_type = error_type_override or type(error).__name__
|
|
257
|
+
|
|
258
|
+
error_message = str(error)
|
|
259
|
+
pattern = cache.create_pattern_from_error(error_message, detected_type)
|
|
260
|
+
|
|
261
|
+
if pattern:
|
|
262
|
+
await cache.add_pattern(pattern)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _cache_exception_sync(
|
|
266
|
+
cache: ErrorCache,
|
|
267
|
+
error: Exception,
|
|
268
|
+
func: t.Callable[..., t.Any],
|
|
269
|
+
error_type_override: str | None,
|
|
270
|
+
) -> None:
|
|
271
|
+
"""Cache a generic exception (sync)."""
|
|
272
|
+
import asyncio
|
|
273
|
+
|
|
274
|
+
get_function_context(func)
|
|
275
|
+
detected_type = error_type_override or type(error).__name__
|
|
276
|
+
|
|
277
|
+
error_message = str(error)
|
|
278
|
+
pattern = cache.create_pattern_from_error(error_message, detected_type)
|
|
279
|
+
|
|
280
|
+
if pattern:
|
|
281
|
+
asyncio.run(cache.add_pattern(pattern))
|