crackerjack 0.18.2__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 +96 -2
- crackerjack/__main__.py +637 -138
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +39 -0
- 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/lsp/_base.py +194 -0
- crackerjack/adapters/lsp/_client.py +358 -0
- crackerjack/adapters/lsp/_manager.py +193 -0
- crackerjack/adapters/lsp/skylos.py +283 -0
- crackerjack/adapters/lsp/zuban.py +557 -0
- 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 +66 -0
- crackerjack/agents/architect_agent.py +238 -0
- crackerjack/agents/base.py +167 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +600 -0
- crackerjack/agents/documentation_agent.py +520 -0
- crackerjack/agents/dry_agent.py +585 -0
- 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 +230 -0
- 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/import_optimization_agent.py +1181 -0
- crackerjack/agents/performance_agent.py +325 -0
- crackerjack/agents/performance_helpers.py +205 -0
- crackerjack/agents/proactive_agent.py +55 -0
- crackerjack/agents/refactoring_agent.py +511 -0
- crackerjack/agents/refactoring_helpers.py +247 -0
- crackerjack/agents/security_agent.py +793 -0
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +570 -0
- crackerjack/agents/test_specialist_agent.py +526 -0
- crackerjack/agents/tracker.py +110 -0
- crackerjack/api.py +647 -0
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +24 -0
- crackerjack/cli/cache_handlers.py +209 -0
- crackerjack/cli/cache_handlers_enhanced.py +680 -0
- crackerjack/cli/facade.py +162 -0
- 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 +700 -0
- crackerjack/cli/interactive.py +488 -0
- crackerjack/cli/options.py +1216 -0
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/utils.py +19 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +1307 -0
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +275 -0
- crackerjack/config/global_lock_config.py +207 -0
- crackerjack/config/hooks.py +390 -0
- 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/__init__.py +0 -0
- crackerjack/core/async_workflow_orchestrator.py +738 -0
- crackerjack/core/autofix_coordinator.py +282 -0
- crackerjack/core/container.py +105 -0
- crackerjack/core/enhanced_container.py +583 -0
- crackerjack/core/file_lifecycle.py +472 -0
- crackerjack/core/performance.py +244 -0
- crackerjack/core/performance_monitor.py +357 -0
- crackerjack/core/phase_coordinator.py +1227 -0
- crackerjack/core/proactive_workflow.py +267 -0
- crackerjack/core/resource_manager.py +425 -0
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +601 -0
- crackerjack/core/session_coordinator.py +239 -0
- crackerjack/core/timeout_manager.py +563 -0
- crackerjack/core/websocket_lifecycle.py +410 -0
- 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 +2243 -0
- 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/INDEX.md +11 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +767 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +1065 -0
- crackerjack/dynamic_config.py +678 -0
- crackerjack/errors.py +378 -0
- 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 +13 -0
- crackerjack/executors/async_hook_executor.py +938 -0
- crackerjack/executors/cached_hook_executor.py +316 -0
- crackerjack/executors/hook_executor.py +1295 -0
- crackerjack/executors/hook_lock_manager.py +708 -0
- crackerjack/executors/individual_hook_executor.py +739 -0
- crackerjack/executors/lsp_aware_hook_executor.py +349 -0
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +433 -0
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +93 -0
- crackerjack/intelligence/README.md +557 -0
- crackerjack/intelligence/__init__.py +37 -0
- crackerjack/intelligence/adaptive_learning.py +693 -0
- crackerjack/intelligence/agent_orchestrator.py +485 -0
- crackerjack/intelligence/agent_registry.py +377 -0
- crackerjack/intelligence/agent_selector.py +439 -0
- crackerjack/intelligence/integration.py +250 -0
- crackerjack/interactive.py +719 -0
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/__init__.py +11 -0
- crackerjack/managers/async_hook_manager.py +135 -0
- crackerjack/managers/hook_manager.py +585 -0
- crackerjack/managers/publish_manager.py +631 -0
- crackerjack/managers/test_command_builder.py +391 -0
- crackerjack/managers/test_executor.py +474 -0
- crackerjack/managers/test_manager.py +1357 -0
- crackerjack/managers/test_progress.py +187 -0
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/__init__.py +0 -0
- crackerjack/mcp/cache.py +352 -0
- crackerjack/mcp/client_runner.py +121 -0
- crackerjack/mcp/context.py +802 -0
- crackerjack/mcp/dashboard.py +657 -0
- crackerjack/mcp/enhanced_progress_monitor.py +493 -0
- crackerjack/mcp/file_monitor.py +394 -0
- crackerjack/mcp/progress_components.py +607 -0
- crackerjack/mcp/progress_monitor.py +1016 -0
- crackerjack/mcp/rate_limiter.py +336 -0
- crackerjack/mcp/server.py +24 -0
- crackerjack/mcp/server_core.py +526 -0
- crackerjack/mcp/service_watchdog.py +505 -0
- crackerjack/mcp/state.py +407 -0
- crackerjack/mcp/task_manager.py +259 -0
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +19 -0
- crackerjack/mcp/tools/core_tools.py +469 -0
- crackerjack/mcp/tools/error_analyzer.py +283 -0
- crackerjack/mcp/tools/execution_tools.py +384 -0
- crackerjack/mcp/tools/intelligence_tool_registry.py +46 -0
- crackerjack/mcp/tools/intelligence_tools.py +264 -0
- crackerjack/mcp/tools/monitoring_tools.py +628 -0
- crackerjack/mcp/tools/proactive_tools.py +367 -0
- crackerjack/mcp/tools/progress_tools.py +222 -0
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +358 -0
- crackerjack/mcp/tools/workflow_executor.py +699 -0
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/__init__.py +14 -0
- crackerjack/mcp/websocket/app.py +54 -0
- crackerjack/mcp/websocket/endpoints.py +492 -0
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +406 -0
- 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 +21 -0
- crackerjack/mcp/websocket/server.py +174 -0
- crackerjack/mcp/websocket/websocket_handler.py +276 -0
- crackerjack/mcp/websocket_server.py +10 -0
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +40 -0
- crackerjack/models/config.py +730 -0
- crackerjack/models/config_adapter.py +265 -0
- crackerjack/models/protocols.py +1535 -0
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/resource_protocols.py +299 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +173 -0
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/__init__.py +0 -0
- crackerjack/monitoring/ai_agent_watchdog.py +405 -0
- crackerjack/monitoring/metrics_collector.py +427 -0
- crackerjack/monitoring/regression_prevention.py +580 -0
- crackerjack/monitoring/websocket_server.py +406 -0
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +894 -0
- 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 +180 -0
- crackerjack/orchestration/execution_strategies.py +361 -0
- 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 +647 -0
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/__init__.py +15 -0
- crackerjack/plugins/base.py +200 -0
- crackerjack/plugins/hooks.py +254 -0
- crackerjack/plugins/loader.py +335 -0
- crackerjack/plugins/managers.py +264 -0
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/security/__init__.py +0 -0
- crackerjack/security/audit.py +197 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +9 -0
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/ai/contextual_ai_assistant.py +542 -0
- 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/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +617 -0
- crackerjack/services/backup_service.py +467 -0
- crackerjack/services/bounded_status_operations.py +530 -0
- crackerjack/services/cache.py +369 -0
- crackerjack/services/changelog_automation.py +399 -0
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +132 -0
- crackerjack/services/config_merge.py +546 -0
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +493 -0
- crackerjack/services/coverage_badge_service.py +173 -0
- crackerjack/services/coverage_ratchet.py +381 -0
- crackerjack/services/debug.py +733 -0
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +622 -0
- crackerjack/services/documentation_generator.py +493 -0
- crackerjack/services/documentation_service.py +704 -0
- crackerjack/services/enhanced_filesystem.py +497 -0
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +149 -0
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +381 -0
- crackerjack/services/git.py +422 -0
- crackerjack/services/health_metrics.py +615 -0
- crackerjack/services/heatmap_generator.py +744 -0
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +823 -0
- crackerjack/services/input_validator.py +668 -0
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +289 -0
- crackerjack/services/logging.py +228 -0
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +414 -0
- crackerjack/services/metrics.py +587 -0
- 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/monitoring/performance_benchmarks.py +410 -0
- crackerjack/services/monitoring/performance_cache.py +388 -0
- crackerjack/services/monitoring/performance_monitor.py +569 -0
- crackerjack/services/parallel_executor.py +527 -0
- crackerjack/services/pattern_cache.py +333 -0
- crackerjack/services/pattern_detector.py +478 -0
- 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 +523 -0
- 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/quality_baseline.py +395 -0
- crackerjack/services/quality/quality_baseline_enhanced.py +649 -0
- crackerjack/services/quality/quality_intelligence.py +949 -0
- crackerjack/services/regex_patterns.py +58 -0
- crackerjack/services/regex_utils.py +483 -0
- crackerjack/services/secure_path_utils.py +524 -0
- crackerjack/services/secure_status_formatter.py +450 -0
- crackerjack/services/secure_subprocess.py +635 -0
- crackerjack/services/security.py +239 -0
- crackerjack/services/security_logger.py +495 -0
- crackerjack/services/server_manager.py +411 -0
- crackerjack/services/smart_scheduling.py +167 -0
- crackerjack/services/status_authentication.py +460 -0
- crackerjack/services/status_security_manager.py +315 -0
- crackerjack/services/terminal_utils.py +0 -0
- crackerjack/services/thread_safe_status_collector.py +441 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +43 -0
- crackerjack/services/unified_config.py +115 -0
- crackerjack/services/validation_rate_limiter.py +220 -0
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +461 -0
- crackerjack/services/version_checker.py +223 -0
- crackerjack/services/websocket_resource_limiter.py +438 -0
- crackerjack/services/zuban_lsp_service.py +391 -0
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/__init__.py +59 -0
- crackerjack/slash_commands/init.md +112 -0
- crackerjack/slash_commands/run.md +197 -0
- crackerjack/slash_commands/status.md +127 -0
- 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_input_validator_patterns.py +236 -0
- crackerjack/tools/validate_regex_patterns.py +188 -0
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/__init__.py +1 -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.45.2.dist-info/METADATA +1678 -0
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack-0.45.2.dist-info/entry_points.txt +2 -0
- crackerjack/.gitignore +0 -14
- crackerjack/.libcst.codemod.yaml +0 -18
- crackerjack/.pdm.toml +0 -1
- crackerjack/.pre-commit-config.yaml +0 -91
- crackerjack/.pytest_cache/.gitignore +0 -2
- crackerjack/.pytest_cache/CACHEDIR.TAG +0 -4
- crackerjack/.pytest_cache/README.md +0 -8
- crackerjack/.pytest_cache/v/cache/nodeids +0 -1
- crackerjack/.pytest_cache/v/cache/stepwise +0 -1
- crackerjack/.ruff_cache/.gitignore +0 -1
- crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
- crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
- crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
- crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
- crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
- crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
- crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
- crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
- crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
- crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
- crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
- crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
- crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
- crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
- crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
- crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
- crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
- crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
- crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
- crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
- crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
- crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
- crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
- crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
- crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
- crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
- crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
- crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
- crackerjack/.ruff_cache/CACHEDIR.TAG +0 -1
- crackerjack/crackerjack.py +0 -855
- crackerjack/pyproject.toml +0 -214
- crackerjack-0.18.2.dist-info/METADATA +0 -420
- crackerjack-0.18.2.dist-info/RECORD +0 -59
- crackerjack-0.18.2.dist-info/entry_points.txt +0 -4
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from collections.abc import Iterator
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from crackerjack.errors import ErrorCode, FileError, ResourceError
|
|
6
|
+
from crackerjack.models.protocols import FileSystemInterface
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FileSystemService(FileSystemInterface):
|
|
10
|
+
@staticmethod
|
|
11
|
+
def clean_trailing_whitespace_and_newlines(content: str) -> str:
|
|
12
|
+
lines = content.splitlines()
|
|
13
|
+
cleaned_lines = [line.rstrip() for line in lines]
|
|
14
|
+
|
|
15
|
+
result = "\n".join(cleaned_lines)
|
|
16
|
+
if result and not result.endswith("\n"):
|
|
17
|
+
result += "\n"
|
|
18
|
+
|
|
19
|
+
return result
|
|
20
|
+
|
|
21
|
+
def _validate_path_exists(self, path_obj: Path, operation: str) -> None:
|
|
22
|
+
"""Validate that a path exists."""
|
|
23
|
+
if not path_obj.exists():
|
|
24
|
+
raise FileError(
|
|
25
|
+
message=f"File does not exist: {path_obj}",
|
|
26
|
+
details=f"Attempted to {operation} file at {path_obj.absolute()}",
|
|
27
|
+
recovery="Check file path and ensure file exists",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def _handle_permission_error(
|
|
31
|
+
self, error: PermissionError, path: str | Path, operation: str
|
|
32
|
+
) -> None:
|
|
33
|
+
"""Handle permission errors."""
|
|
34
|
+
raise FileError(
|
|
35
|
+
message=f"Permission denied {operation}: {path}",
|
|
36
|
+
error_code=ErrorCode.PERMISSION_ERROR,
|
|
37
|
+
details=str(error),
|
|
38
|
+
recovery="Check file permissions and user access rights",
|
|
39
|
+
) from error
|
|
40
|
+
|
|
41
|
+
def _handle_unicode_error(
|
|
42
|
+
self, error: UnicodeDecodeError, path: str | Path
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Handle unicode decode errors."""
|
|
45
|
+
raise FileError(
|
|
46
|
+
message=f"Unable to decode file as UTF-8: {path}",
|
|
47
|
+
error_code=ErrorCode.FILE_READ_ERROR,
|
|
48
|
+
details=str(error),
|
|
49
|
+
recovery="Ensure file is text - based and UTF-8 encoded",
|
|
50
|
+
) from error
|
|
51
|
+
|
|
52
|
+
def _handle_os_error(
|
|
53
|
+
self, error: OSError, path: str | Path, operation: str
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Handle OS errors."""
|
|
56
|
+
raise FileError(
|
|
57
|
+
message=f"System error {operation}: {path}",
|
|
58
|
+
error_code=ErrorCode.FILE_READ_ERROR,
|
|
59
|
+
details=str(error),
|
|
60
|
+
recovery="Check disk space and file system integrity",
|
|
61
|
+
) from error
|
|
62
|
+
|
|
63
|
+
def _handle_disk_space_error(
|
|
64
|
+
self, error: OSError, path: str | Path, operation: str
|
|
65
|
+
) -> None:
|
|
66
|
+
"""Handle disk space errors."""
|
|
67
|
+
if "No space left on device" in str(error):
|
|
68
|
+
raise ResourceError(
|
|
69
|
+
message=f"Insufficient disk space to {operation}: {path}",
|
|
70
|
+
details=str(error),
|
|
71
|
+
recovery="Free up disk space and try again",
|
|
72
|
+
) from error
|
|
73
|
+
raise FileError(
|
|
74
|
+
message=f"System error {operation}: {path}",
|
|
75
|
+
error_code=ErrorCode.FILE_WRITE_ERROR,
|
|
76
|
+
details=str(error),
|
|
77
|
+
recovery="Check disk space and file system integrity",
|
|
78
|
+
) from error
|
|
79
|
+
|
|
80
|
+
def read_file(self, path: str | Path) -> str:
|
|
81
|
+
try:
|
|
82
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
83
|
+
self._validate_path_exists(path_obj, "read")
|
|
84
|
+
return path_obj.read_text(encoding="utf-8")
|
|
85
|
+
except PermissionError as e:
|
|
86
|
+
self._handle_permission_error(e, path, "reading file")
|
|
87
|
+
raise # Ensure type checker knows this doesn't return
|
|
88
|
+
except UnicodeDecodeError as e:
|
|
89
|
+
self._handle_unicode_error(e, path)
|
|
90
|
+
raise # Ensure type checker knows this doesn't return
|
|
91
|
+
except OSError as e:
|
|
92
|
+
self._handle_os_error(e, path, "reading file")
|
|
93
|
+
raise # Ensure type checker knows this doesn't return
|
|
94
|
+
|
|
95
|
+
def write_file(self, path: str | Path, content: str) -> None:
|
|
96
|
+
try:
|
|
97
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
98
|
+
try:
|
|
99
|
+
path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
100
|
+
except OSError as e:
|
|
101
|
+
raise FileError(
|
|
102
|
+
message=f"Cannot create parent directories for: {path}",
|
|
103
|
+
error_code=ErrorCode.FILE_WRITE_ERROR,
|
|
104
|
+
details=str(e),
|
|
105
|
+
recovery="Check disk space and directory permissions",
|
|
106
|
+
) from e
|
|
107
|
+
|
|
108
|
+
if path_obj.name in {".pre-commit-config.yaml", "pyproject.toml"}:
|
|
109
|
+
content = self.clean_trailing_whitespace_and_newlines(content)
|
|
110
|
+
|
|
111
|
+
path_obj.write_text(content, encoding="utf-8")
|
|
112
|
+
except PermissionError as e:
|
|
113
|
+
raise FileError(
|
|
114
|
+
message=f"Permission denied writing file: {path}",
|
|
115
|
+
error_code=ErrorCode.PERMISSION_ERROR,
|
|
116
|
+
details=str(e),
|
|
117
|
+
recovery="Check file and directory permissions",
|
|
118
|
+
) from e
|
|
119
|
+
except OSError as e:
|
|
120
|
+
if "No space left on device" in str(e):
|
|
121
|
+
raise ResourceError(
|
|
122
|
+
message=f"Insufficient disk space to write file: {path}",
|
|
123
|
+
details=str(e),
|
|
124
|
+
recovery="Free up disk space and try again",
|
|
125
|
+
) from e
|
|
126
|
+
raise FileError(
|
|
127
|
+
message=f"System error writing file: {path}",
|
|
128
|
+
error_code=ErrorCode.FILE_WRITE_ERROR,
|
|
129
|
+
details=str(e),
|
|
130
|
+
recovery="Check disk space and file system integrity",
|
|
131
|
+
) from e
|
|
132
|
+
|
|
133
|
+
def exists(self, path: str | Path) -> bool:
|
|
134
|
+
try:
|
|
135
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
136
|
+
return path_obj.exists()
|
|
137
|
+
except OSError:
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
def mkdir(self, path: str | Path, parents: bool = False) -> None:
|
|
141
|
+
try:
|
|
142
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
143
|
+
path_obj.mkdir(parents=parents, exist_ok=True)
|
|
144
|
+
except PermissionError as e:
|
|
145
|
+
self._handle_permission_error(e, path, "creating directory")
|
|
146
|
+
except FileExistsError as e:
|
|
147
|
+
if not parents:
|
|
148
|
+
raise FileError(
|
|
149
|
+
message=f"Directory already exists: {path}",
|
|
150
|
+
details=str(e),
|
|
151
|
+
recovery="Use exist_ok=True or check if directory exists first",
|
|
152
|
+
) from e
|
|
153
|
+
except OSError as e:
|
|
154
|
+
self._handle_disk_space_error(e, path, "create directory")
|
|
155
|
+
|
|
156
|
+
def glob(self, pattern: str, path: str | Path | None = None) -> list[Path]:
|
|
157
|
+
base_path = Path(path) if path else Path.cwd()
|
|
158
|
+
try:
|
|
159
|
+
if not base_path.exists():
|
|
160
|
+
raise FileError(
|
|
161
|
+
message=f"Base path does not exist: {base_path}",
|
|
162
|
+
details=f"Attempted to glob in {base_path.absolute()}",
|
|
163
|
+
recovery="Check base path and ensure directory exists",
|
|
164
|
+
)
|
|
165
|
+
return list(base_path.glob(pattern))
|
|
166
|
+
except PermissionError as e:
|
|
167
|
+
raise FileError(
|
|
168
|
+
message=f"Permission denied accessing directory: {base_path}",
|
|
169
|
+
error_code=ErrorCode.PERMISSION_ERROR,
|
|
170
|
+
details=str(e),
|
|
171
|
+
recovery="Check directory permissions",
|
|
172
|
+
) from e
|
|
173
|
+
except OSError as e:
|
|
174
|
+
raise FileError(
|
|
175
|
+
message=f"System error during glob operation: {pattern}",
|
|
176
|
+
error_code=ErrorCode.FILE_READ_ERROR,
|
|
177
|
+
details=str(e),
|
|
178
|
+
recovery="Check path validity and file system integrity",
|
|
179
|
+
) from e
|
|
180
|
+
|
|
181
|
+
def rglob(self, pattern: str, path: str | Path | None = None) -> list[Path]:
|
|
182
|
+
base_path = Path(path) if path else Path.cwd()
|
|
183
|
+
try:
|
|
184
|
+
if not base_path.exists():
|
|
185
|
+
raise FileError(
|
|
186
|
+
message=f"Base path does not exist: {base_path}",
|
|
187
|
+
details=f"Attempted to rglob in {base_path.absolute()}",
|
|
188
|
+
recovery="Check base path and ensure directory exists",
|
|
189
|
+
)
|
|
190
|
+
return list(base_path.rglob(pattern))
|
|
191
|
+
except PermissionError as e:
|
|
192
|
+
raise FileError(
|
|
193
|
+
message=f"Permission denied accessing directory: {base_path}",
|
|
194
|
+
error_code=ErrorCode.PERMISSION_ERROR,
|
|
195
|
+
details=str(e),
|
|
196
|
+
recovery="Check directory permissions",
|
|
197
|
+
) from e
|
|
198
|
+
except OSError as e:
|
|
199
|
+
raise FileError(
|
|
200
|
+
message=f"System error during recursive glob operation: {pattern}",
|
|
201
|
+
error_code=ErrorCode.FILE_READ_ERROR,
|
|
202
|
+
details=str(e),
|
|
203
|
+
recovery="Check path validity and file system integrity",
|
|
204
|
+
) from e
|
|
205
|
+
|
|
206
|
+
def copy_file(self, src: str | Path, dst: str | Path) -> None:
|
|
207
|
+
src_path, dst_path = self._normalize_copy_paths(src, dst)
|
|
208
|
+
self._validate_copy_source(src_path)
|
|
209
|
+
self._prepare_copy_destination(dst_path)
|
|
210
|
+
self._perform_file_copy(src_path, dst_path, src, dst)
|
|
211
|
+
|
|
212
|
+
def _normalize_copy_paths(
|
|
213
|
+
self, src: str | Path, dst: str | Path
|
|
214
|
+
) -> tuple[Path, Path]:
|
|
215
|
+
src_path = Path(src) if isinstance(src, str) else src
|
|
216
|
+
dst_path = Path(dst) if isinstance(dst, str) else dst
|
|
217
|
+
return src_path, dst_path
|
|
218
|
+
|
|
219
|
+
def _validate_copy_source(self, src_path: Path) -> None:
|
|
220
|
+
if not src_path.exists():
|
|
221
|
+
raise FileError(
|
|
222
|
+
message=f"Source file does not exist: {src_path}",
|
|
223
|
+
details=f"Attempted to copy from {src_path.absolute()}",
|
|
224
|
+
recovery="Check source file path and ensure file exists",
|
|
225
|
+
)
|
|
226
|
+
if not src_path.is_file():
|
|
227
|
+
raise FileError(
|
|
228
|
+
message=f"Source is not a file: {src_path}",
|
|
229
|
+
details=f"Source is a {src_path.stat().st_mode} type",
|
|
230
|
+
recovery="Ensure source path points to a regular file",
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def _prepare_copy_destination(self, dst_path: Path) -> None:
|
|
234
|
+
try:
|
|
235
|
+
dst_path.parent.mkdir(parents=True, exist_ok=True)
|
|
236
|
+
except OSError as e:
|
|
237
|
+
raise FileError(
|
|
238
|
+
message=f"Cannot create destination parent directories: {dst_path.parent}",
|
|
239
|
+
error_code=ErrorCode.FILE_WRITE_ERROR,
|
|
240
|
+
details=str(e),
|
|
241
|
+
recovery="Check disk space and directory permissions",
|
|
242
|
+
) from e
|
|
243
|
+
|
|
244
|
+
def _perform_file_copy(
|
|
245
|
+
self, src_path: Path, dst_path: Path, src: str | Path, dst: str | Path
|
|
246
|
+
) -> None:
|
|
247
|
+
try:
|
|
248
|
+
shutil.copy2(src_path, dst_path)
|
|
249
|
+
except PermissionError as e:
|
|
250
|
+
self._handle_permission_error(e, f"{src} -> {dst}", "copying file")
|
|
251
|
+
except shutil.SameFileError as e:
|
|
252
|
+
raise FileError(
|
|
253
|
+
message=f"Source and destination are the same file: {src}",
|
|
254
|
+
error_code=ErrorCode.FILE_WRITE_ERROR,
|
|
255
|
+
details=str(e),
|
|
256
|
+
recovery="Ensure source and destination paths are different",
|
|
257
|
+
) from e
|
|
258
|
+
except OSError as e:
|
|
259
|
+
self._handle_disk_space_error(e, f"{src} -> {dst}", "copy file")
|
|
260
|
+
|
|
261
|
+
def remove_file(self, path: str | Path) -> None:
|
|
262
|
+
try:
|
|
263
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
264
|
+
if path_obj.exists():
|
|
265
|
+
if not path_obj.is_file():
|
|
266
|
+
raise FileError(
|
|
267
|
+
message=f"Path is not a file: {path_obj}",
|
|
268
|
+
details=f"Path type: {path_obj.stat().st_mode}",
|
|
269
|
+
recovery="Use appropriate method for directory removal",
|
|
270
|
+
)
|
|
271
|
+
path_obj.unlink()
|
|
272
|
+
except PermissionError as e:
|
|
273
|
+
raise FileError(
|
|
274
|
+
message=f"Permission denied removing file: {path}",
|
|
275
|
+
error_code=ErrorCode.PERMISSION_ERROR,
|
|
276
|
+
details=str(e),
|
|
277
|
+
recovery="Check file permissions and ownership",
|
|
278
|
+
) from e
|
|
279
|
+
except OSError as e:
|
|
280
|
+
raise FileError(
|
|
281
|
+
message=f"System error removing file: {path}",
|
|
282
|
+
error_code=ErrorCode.FILE_WRITE_ERROR,
|
|
283
|
+
details=str(e),
|
|
284
|
+
recovery="Check file system integrity and try again",
|
|
285
|
+
) from e
|
|
286
|
+
|
|
287
|
+
def get_file_size(self, path: str | Path) -> int:
|
|
288
|
+
try:
|
|
289
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
290
|
+
if not path_obj.exists():
|
|
291
|
+
raise FileError(
|
|
292
|
+
message=f"File does not exist: {path_obj}",
|
|
293
|
+
details=f"Attempted to get size of {path_obj.absolute()}",
|
|
294
|
+
recovery="Check file path and ensure file exists",
|
|
295
|
+
)
|
|
296
|
+
if not path_obj.is_file():
|
|
297
|
+
raise FileError(
|
|
298
|
+
message=f"Path is not a file: {path_obj}",
|
|
299
|
+
details=f"Path type: {path_obj.stat().st_mode}",
|
|
300
|
+
recovery="Ensure path points to a regular file",
|
|
301
|
+
)
|
|
302
|
+
return path_obj.stat().st_size
|
|
303
|
+
except PermissionError as e:
|
|
304
|
+
raise FileError(
|
|
305
|
+
message=f"Permission denied accessing file: {path}",
|
|
306
|
+
error_code=ErrorCode.PERMISSION_ERROR,
|
|
307
|
+
details=str(e),
|
|
308
|
+
recovery="Check file permissions",
|
|
309
|
+
) from e
|
|
310
|
+
except OSError as e:
|
|
311
|
+
raise FileError(
|
|
312
|
+
message=f"System error getting file size: {path}",
|
|
313
|
+
error_code=ErrorCode.FILE_READ_ERROR,
|
|
314
|
+
details=str(e),
|
|
315
|
+
recovery="Check file system integrity",
|
|
316
|
+
) from e
|
|
317
|
+
|
|
318
|
+
def get_file_mtime(self, path: str | Path) -> float:
|
|
319
|
+
try:
|
|
320
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
321
|
+
if not path_obj.exists():
|
|
322
|
+
raise FileError(
|
|
323
|
+
message=f"File does not exist: {path_obj}",
|
|
324
|
+
details=f"Attempted to get mtime of {path_obj.absolute()}",
|
|
325
|
+
recovery="Check file path and ensure file exists",
|
|
326
|
+
)
|
|
327
|
+
if not path_obj.is_file():
|
|
328
|
+
raise FileError(
|
|
329
|
+
message=f"Path is not a file: {path_obj}",
|
|
330
|
+
details=f"Path type: {path_obj.stat().st_mode}",
|
|
331
|
+
recovery="Ensure path points to a regular file",
|
|
332
|
+
)
|
|
333
|
+
return path_obj.stat().st_mtime
|
|
334
|
+
except PermissionError as e:
|
|
335
|
+
raise FileError(
|
|
336
|
+
message=f"Permission denied accessing file: {path}",
|
|
337
|
+
error_code=ErrorCode.PERMISSION_ERROR,
|
|
338
|
+
details=str(e),
|
|
339
|
+
recovery="Check file permissions",
|
|
340
|
+
) from e
|
|
341
|
+
except OSError as e:
|
|
342
|
+
raise FileError(
|
|
343
|
+
message=f"System error getting file modification time: {path}",
|
|
344
|
+
error_code=ErrorCode.FILE_READ_ERROR,
|
|
345
|
+
details=str(e),
|
|
346
|
+
recovery="Check file system integrity",
|
|
347
|
+
) from e
|
|
348
|
+
|
|
349
|
+
def read_file_chunked(
|
|
350
|
+
self,
|
|
351
|
+
path: str | Path,
|
|
352
|
+
chunk_size: int = 8192,
|
|
353
|
+
) -> Iterator[str]:
|
|
354
|
+
try:
|
|
355
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
356
|
+
self._validate_path_exists(path_obj, "read")
|
|
357
|
+
|
|
358
|
+
with path_obj.open(encoding="utf-8") as file:
|
|
359
|
+
while chunk := file.read(chunk_size):
|
|
360
|
+
yield chunk
|
|
361
|
+
|
|
362
|
+
except PermissionError as e:
|
|
363
|
+
self._handle_permission_error(e, path, "reading file")
|
|
364
|
+
except UnicodeDecodeError as e:
|
|
365
|
+
self._handle_unicode_error(e, path)
|
|
366
|
+
except OSError as e:
|
|
367
|
+
self._handle_os_error(e, path, "reading file")
|
|
368
|
+
|
|
369
|
+
def read_lines_streaming(self, path: str | Path) -> Iterator[str]:
|
|
370
|
+
try:
|
|
371
|
+
path_obj = Path(path) if isinstance(path, str) else path
|
|
372
|
+
self._validate_path_exists(path_obj, "read")
|
|
373
|
+
with path_obj.open(encoding="utf-8") as file:
|
|
374
|
+
for line in file:
|
|
375
|
+
yield line.rstrip("\n\r")
|
|
376
|
+
except PermissionError as e:
|
|
377
|
+
self._handle_permission_error(e, path, "reading file")
|
|
378
|
+
except UnicodeDecodeError as e:
|
|
379
|
+
self._handle_unicode_error(e, path)
|
|
380
|
+
except OSError as e:
|
|
381
|
+
self._handle_os_error(e, path, "reading file")
|