crackerjack 0.29.0__py3-none-any.whl โ 0.31.4__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.
Potentially problematic release.
This version of crackerjack might be problematic. Click here for more details.
- crackerjack/CLAUDE.md +1005 -0
- crackerjack/RULES.md +380 -0
- crackerjack/__init__.py +42 -13
- crackerjack/__main__.py +225 -253
- crackerjack/agents/__init__.py +41 -0
- crackerjack/agents/architect_agent.py +281 -0
- crackerjack/agents/base.py +169 -0
- crackerjack/agents/coordinator.py +512 -0
- crackerjack/agents/documentation_agent.py +498 -0
- crackerjack/agents/dry_agent.py +388 -0
- crackerjack/agents/formatting_agent.py +245 -0
- crackerjack/agents/import_optimization_agent.py +281 -0
- crackerjack/agents/performance_agent.py +669 -0
- crackerjack/agents/proactive_agent.py +104 -0
- crackerjack/agents/refactoring_agent.py +788 -0
- crackerjack/agents/security_agent.py +529 -0
- crackerjack/agents/test_creation_agent.py +652 -0
- crackerjack/agents/test_specialist_agent.py +486 -0
- crackerjack/agents/tracker.py +212 -0
- crackerjack/api.py +560 -0
- crackerjack/cli/__init__.py +24 -0
- crackerjack/cli/facade.py +104 -0
- crackerjack/cli/handlers.py +267 -0
- crackerjack/cli/interactive.py +471 -0
- crackerjack/cli/options.py +401 -0
- crackerjack/cli/utils.py +18 -0
- crackerjack/code_cleaner.py +670 -0
- crackerjack/config/__init__.py +19 -0
- crackerjack/config/hooks.py +218 -0
- crackerjack/core/__init__.py +0 -0
- crackerjack/core/async_workflow_orchestrator.py +406 -0
- crackerjack/core/autofix_coordinator.py +200 -0
- crackerjack/core/container.py +104 -0
- crackerjack/core/enhanced_container.py +542 -0
- crackerjack/core/performance.py +243 -0
- crackerjack/core/phase_coordinator.py +561 -0
- crackerjack/core/proactive_workflow.py +316 -0
- crackerjack/core/session_coordinator.py +289 -0
- crackerjack/core/workflow_orchestrator.py +640 -0
- crackerjack/dynamic_config.py +577 -0
- crackerjack/errors.py +263 -41
- crackerjack/executors/__init__.py +11 -0
- crackerjack/executors/async_hook_executor.py +431 -0
- crackerjack/executors/cached_hook_executor.py +242 -0
- crackerjack/executors/hook_executor.py +345 -0
- crackerjack/executors/individual_hook_executor.py +669 -0
- crackerjack/intelligence/__init__.py +44 -0
- crackerjack/intelligence/adaptive_learning.py +751 -0
- crackerjack/intelligence/agent_orchestrator.py +551 -0
- crackerjack/intelligence/agent_registry.py +414 -0
- crackerjack/intelligence/agent_selector.py +502 -0
- crackerjack/intelligence/integration.py +290 -0
- crackerjack/interactive.py +576 -315
- crackerjack/managers/__init__.py +11 -0
- crackerjack/managers/async_hook_manager.py +135 -0
- crackerjack/managers/hook_manager.py +137 -0
- crackerjack/managers/publish_manager.py +411 -0
- crackerjack/managers/test_command_builder.py +151 -0
- crackerjack/managers/test_executor.py +435 -0
- crackerjack/managers/test_manager.py +258 -0
- crackerjack/managers/test_manager_backup.py +1124 -0
- crackerjack/managers/test_progress.py +144 -0
- crackerjack/mcp/__init__.py +0 -0
- crackerjack/mcp/cache.py +336 -0
- crackerjack/mcp/client_runner.py +104 -0
- crackerjack/mcp/context.py +615 -0
- crackerjack/mcp/dashboard.py +636 -0
- crackerjack/mcp/enhanced_progress_monitor.py +479 -0
- crackerjack/mcp/file_monitor.py +336 -0
- crackerjack/mcp/progress_components.py +569 -0
- crackerjack/mcp/progress_monitor.py +949 -0
- crackerjack/mcp/rate_limiter.py +332 -0
- crackerjack/mcp/server.py +22 -0
- crackerjack/mcp/server_core.py +244 -0
- crackerjack/mcp/service_watchdog.py +501 -0
- crackerjack/mcp/state.py +395 -0
- crackerjack/mcp/task_manager.py +257 -0
- crackerjack/mcp/tools/__init__.py +17 -0
- crackerjack/mcp/tools/core_tools.py +249 -0
- crackerjack/mcp/tools/error_analyzer.py +308 -0
- crackerjack/mcp/tools/execution_tools.py +370 -0
- crackerjack/mcp/tools/execution_tools_backup.py +1097 -0
- crackerjack/mcp/tools/intelligence_tool_registry.py +80 -0
- crackerjack/mcp/tools/intelligence_tools.py +314 -0
- crackerjack/mcp/tools/monitoring_tools.py +502 -0
- crackerjack/mcp/tools/proactive_tools.py +384 -0
- crackerjack/mcp/tools/progress_tools.py +141 -0
- crackerjack/mcp/tools/utility_tools.py +341 -0
- crackerjack/mcp/tools/workflow_executor.py +360 -0
- crackerjack/mcp/websocket/__init__.py +14 -0
- crackerjack/mcp/websocket/app.py +39 -0
- crackerjack/mcp/websocket/endpoints.py +559 -0
- crackerjack/mcp/websocket/jobs.py +253 -0
- crackerjack/mcp/websocket/server.py +116 -0
- crackerjack/mcp/websocket/websocket_handler.py +78 -0
- crackerjack/mcp/websocket_server.py +10 -0
- crackerjack/models/__init__.py +31 -0
- crackerjack/models/config.py +93 -0
- crackerjack/models/config_adapter.py +230 -0
- crackerjack/models/protocols.py +118 -0
- crackerjack/models/task.py +154 -0
- crackerjack/monitoring/ai_agent_watchdog.py +450 -0
- crackerjack/monitoring/regression_prevention.py +638 -0
- crackerjack/orchestration/__init__.py +0 -0
- crackerjack/orchestration/advanced_orchestrator.py +970 -0
- crackerjack/orchestration/execution_strategies.py +341 -0
- crackerjack/orchestration/test_progress_streamer.py +636 -0
- crackerjack/plugins/__init__.py +15 -0
- crackerjack/plugins/base.py +200 -0
- crackerjack/plugins/hooks.py +246 -0
- crackerjack/plugins/loader.py +335 -0
- crackerjack/plugins/managers.py +259 -0
- crackerjack/py313.py +8 -3
- crackerjack/services/__init__.py +22 -0
- crackerjack/services/cache.py +314 -0
- crackerjack/services/config.py +347 -0
- crackerjack/services/config_integrity.py +99 -0
- crackerjack/services/contextual_ai_assistant.py +516 -0
- crackerjack/services/coverage_ratchet.py +347 -0
- crackerjack/services/debug.py +736 -0
- crackerjack/services/dependency_monitor.py +617 -0
- crackerjack/services/enhanced_filesystem.py +439 -0
- crackerjack/services/file_hasher.py +151 -0
- crackerjack/services/filesystem.py +395 -0
- crackerjack/services/git.py +165 -0
- crackerjack/services/health_metrics.py +611 -0
- crackerjack/services/initialization.py +847 -0
- crackerjack/services/log_manager.py +286 -0
- crackerjack/services/logging.py +174 -0
- crackerjack/services/metrics.py +578 -0
- crackerjack/services/pattern_cache.py +362 -0
- crackerjack/services/pattern_detector.py +515 -0
- crackerjack/services/performance_benchmarks.py +653 -0
- crackerjack/services/security.py +163 -0
- crackerjack/services/server_manager.py +234 -0
- crackerjack/services/smart_scheduling.py +144 -0
- crackerjack/services/tool_version_service.py +61 -0
- crackerjack/services/unified_config.py +437 -0
- crackerjack/services/version_checker.py +248 -0
- crackerjack/slash_commands/__init__.py +14 -0
- crackerjack/slash_commands/init.md +122 -0
- crackerjack/slash_commands/run.md +163 -0
- crackerjack/slash_commands/status.md +127 -0
- crackerjack-0.31.4.dist-info/METADATA +742 -0
- crackerjack-0.31.4.dist-info/RECORD +148 -0
- crackerjack-0.31.4.dist-info/entry_points.txt +2 -0
- crackerjack/.gitignore +0 -34
- crackerjack/.libcst.codemod.yaml +0 -18
- crackerjack/.pdm.toml +0 -1
- crackerjack/.pre-commit-config-ai.yaml +0 -149
- crackerjack/.pre-commit-config-fast.yaml +0 -69
- crackerjack/.pre-commit-config.yaml +0 -114
- crackerjack/crackerjack.py +0 -4140
- crackerjack/pyproject.toml +0 -285
- crackerjack-0.29.0.dist-info/METADATA +0 -1289
- crackerjack-0.29.0.dist-info/RECORD +0 -17
- {crackerjack-0.29.0.dist-info โ crackerjack-0.31.4.dist-info}/WHEEL +0 -0
- {crackerjack-0.29.0.dist-info โ crackerjack-0.31.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""Refactored test manager with focused responsibilities.
|
|
2
|
+
|
|
3
|
+
This is the new modular test manager that delegates to specialized components:
|
|
4
|
+
- TestExecutor: Handles test execution and progress tracking
|
|
5
|
+
- TestCommandBuilder: Builds pytest commands with appropriate options
|
|
6
|
+
- TestProgress: Tracks and displays test progress
|
|
7
|
+
- CoverageRatchetService: Manages coverage requirements
|
|
8
|
+
|
|
9
|
+
REFACTORING NOTE: Original test_manager.py was 1133 lines with 60+ methods.
|
|
10
|
+
This refactored version is ~200 lines and delegates to focused modules.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import subprocess
|
|
14
|
+
import time
|
|
15
|
+
import typing as t
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from rich.console import Console
|
|
19
|
+
|
|
20
|
+
from crackerjack.models.protocols import OptionsProtocol
|
|
21
|
+
from crackerjack.services.coverage_ratchet import CoverageRatchetService
|
|
22
|
+
|
|
23
|
+
from .test_command_builder import TestCommandBuilder
|
|
24
|
+
from .test_executor import TestExecutor
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TestManager:
|
|
28
|
+
"""Refactored test manager with modular architecture."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, console: Console, pkg_path: Path) -> None:
|
|
31
|
+
self.console = console
|
|
32
|
+
self.pkg_path = pkg_path
|
|
33
|
+
|
|
34
|
+
# Initialize specialized components
|
|
35
|
+
self.executor = TestExecutor(console, pkg_path)
|
|
36
|
+
self.command_builder = TestCommandBuilder(pkg_path)
|
|
37
|
+
self.coverage_ratchet = CoverageRatchetService(pkg_path, console)
|
|
38
|
+
|
|
39
|
+
# State
|
|
40
|
+
self._last_test_failures: list[str] = []
|
|
41
|
+
self._progress_callback: t.Callable[[dict[str, t.Any]], None] | None = None
|
|
42
|
+
self.coverage_ratchet_enabled = True
|
|
43
|
+
|
|
44
|
+
def set_progress_callback(
|
|
45
|
+
self,
|
|
46
|
+
callback: t.Callable[[dict[str, t.Any]], None] | None,
|
|
47
|
+
) -> None:
|
|
48
|
+
"""Set callback for AI mode structured progress updates."""
|
|
49
|
+
self._progress_callback = callback
|
|
50
|
+
|
|
51
|
+
def set_coverage_ratchet_enabled(self, enabled: bool) -> None:
|
|
52
|
+
"""Enable or disable the coverage ratchet system."""
|
|
53
|
+
self.coverage_ratchet_enabled = enabled
|
|
54
|
+
if enabled:
|
|
55
|
+
self.console.print(
|
|
56
|
+
"[cyan]๐[/cyan] Coverage ratchet enabled - targeting 100% coverage"
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
self.console.print("[yellow]โ ๏ธ[/yellow] Coverage ratchet disabled")
|
|
60
|
+
|
|
61
|
+
def run_tests(self, options: OptionsProtocol) -> bool:
|
|
62
|
+
"""Run tests with comprehensive progress tracking and coverage analysis."""
|
|
63
|
+
start_time = time.time()
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
result = self._execute_test_workflow(options)
|
|
67
|
+
duration = time.time() - start_time
|
|
68
|
+
|
|
69
|
+
if result:
|
|
70
|
+
return self._handle_test_success(result.stdout, duration)
|
|
71
|
+
else:
|
|
72
|
+
return self._handle_test_failure(
|
|
73
|
+
result.stderr if result else "", duration
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
except Exception as e:
|
|
77
|
+
return self._handle_test_error(start_time, e)
|
|
78
|
+
|
|
79
|
+
def run_specific_tests(self, test_pattern: str) -> bool:
|
|
80
|
+
"""Run tests matching a specific pattern."""
|
|
81
|
+
self.console.print(f"[cyan]๐งช[/cyan] Running tests matching: {test_pattern}")
|
|
82
|
+
|
|
83
|
+
cmd = self.command_builder.build_specific_test_command(test_pattern)
|
|
84
|
+
result = self.executor.execute_with_progress(cmd)
|
|
85
|
+
|
|
86
|
+
success = result.returncode == 0
|
|
87
|
+
if success:
|
|
88
|
+
self.console.print("[green]โ
[/green] Specific tests passed")
|
|
89
|
+
else:
|
|
90
|
+
self.console.print("[red]โ[/red] Some specific tests failed")
|
|
91
|
+
|
|
92
|
+
return success
|
|
93
|
+
|
|
94
|
+
def validate_test_environment(self) -> bool:
|
|
95
|
+
"""Validate test environment and configuration."""
|
|
96
|
+
if not self.has_tests():
|
|
97
|
+
self.console.print("[yellow]โ ๏ธ[/yellow] No tests found")
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
# Test basic pytest collection
|
|
101
|
+
cmd = self.command_builder.build_validation_command()
|
|
102
|
+
result = subprocess.run(cmd, cwd=self.pkg_path, capture_output=True, text=True)
|
|
103
|
+
|
|
104
|
+
if result.returncode != 0:
|
|
105
|
+
self.console.print("[red]โ[/red] Test environment validation failed")
|
|
106
|
+
self.console.print(result.stderr)
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
self.console.print("[green]โ
[/green] Test environment validated")
|
|
110
|
+
return True
|
|
111
|
+
|
|
112
|
+
def get_coverage_ratchet_status(self) -> dict[str, t.Any]:
|
|
113
|
+
"""Get comprehensive coverage ratchet status."""
|
|
114
|
+
return self.coverage_ratchet.get_status_report()
|
|
115
|
+
|
|
116
|
+
def get_test_stats(self) -> dict[str, t.Any]:
|
|
117
|
+
"""Get comprehensive test execution statistics."""
|
|
118
|
+
return {
|
|
119
|
+
"has_tests": self.has_tests(),
|
|
120
|
+
"coverage_ratchet_enabled": self.coverage_ratchet_enabled,
|
|
121
|
+
"last_failures_count": len(self._last_test_failures),
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
def get_test_failures(self) -> list[str]:
|
|
125
|
+
"""Get list of recent test failures."""
|
|
126
|
+
return self._last_test_failures.copy()
|
|
127
|
+
|
|
128
|
+
def get_test_command(self, options: OptionsProtocol) -> list[str]:
|
|
129
|
+
"""Get the test command that would be executed."""
|
|
130
|
+
return self.command_builder.build_command(options)
|
|
131
|
+
|
|
132
|
+
def get_coverage_report(self) -> str | None:
|
|
133
|
+
"""Get coverage report if available."""
|
|
134
|
+
try:
|
|
135
|
+
return self.coverage_ratchet.get_coverage_report()
|
|
136
|
+
except Exception:
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
def has_tests(self) -> bool:
|
|
140
|
+
"""Check if project has tests."""
|
|
141
|
+
test_directories = ["tests", "test"]
|
|
142
|
+
test_files = ["test_*.py", "*_test.py"]
|
|
143
|
+
|
|
144
|
+
for test_dir in test_directories:
|
|
145
|
+
test_path = self.pkg_path / test_dir
|
|
146
|
+
if test_path.exists() and test_path.is_dir():
|
|
147
|
+
for test_file_pattern in test_files:
|
|
148
|
+
if list(test_path.glob(f"**/{test_file_pattern}")):
|
|
149
|
+
return True
|
|
150
|
+
|
|
151
|
+
# Check for test files in root directory
|
|
152
|
+
for test_file_pattern in test_files:
|
|
153
|
+
if list(self.pkg_path.glob(test_file_pattern)):
|
|
154
|
+
return True
|
|
155
|
+
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
# Private implementation methods
|
|
159
|
+
|
|
160
|
+
def _execute_test_workflow(
|
|
161
|
+
self, options: OptionsProtocol
|
|
162
|
+
) -> subprocess.CompletedProcess[str]:
|
|
163
|
+
"""Execute the complete test workflow."""
|
|
164
|
+
self._print_test_start_message(options)
|
|
165
|
+
|
|
166
|
+
cmd = self.command_builder.build_command(options)
|
|
167
|
+
|
|
168
|
+
if self._progress_callback:
|
|
169
|
+
return self.executor.execute_with_ai_progress(
|
|
170
|
+
cmd, self._progress_callback, self._get_timeout(options)
|
|
171
|
+
)
|
|
172
|
+
return self.executor.execute_with_progress(cmd, self._get_timeout(options))
|
|
173
|
+
|
|
174
|
+
def _print_test_start_message(self, options: OptionsProtocol) -> None:
|
|
175
|
+
"""Print test execution start message."""
|
|
176
|
+
workers = self.command_builder.get_optimal_workers(options)
|
|
177
|
+
timeout = self.command_builder.get_test_timeout(options)
|
|
178
|
+
|
|
179
|
+
self.console.print(
|
|
180
|
+
f"[cyan]๐งช[/cyan] Running tests (workers: {workers}, timeout: {timeout}s)"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
def _handle_test_success(self, output: str, duration: float) -> bool:
|
|
184
|
+
"""Handle successful test execution."""
|
|
185
|
+
self.console.print(f"[green]โ
[/green] Tests passed in {duration:.1f}s")
|
|
186
|
+
|
|
187
|
+
if self.coverage_ratchet_enabled:
|
|
188
|
+
return self._process_coverage_ratchet()
|
|
189
|
+
|
|
190
|
+
return True
|
|
191
|
+
|
|
192
|
+
def _handle_test_failure(self, output: str, duration: float) -> bool:
|
|
193
|
+
"""Handle failed test execution."""
|
|
194
|
+
self.console.print(f"[red]โ[/red] Tests failed in {duration:.1f}s")
|
|
195
|
+
|
|
196
|
+
self._last_test_failures = self._extract_failure_lines(output)
|
|
197
|
+
return False
|
|
198
|
+
|
|
199
|
+
def _handle_test_error(self, start_time: float, error: Exception) -> bool:
|
|
200
|
+
"""Handle test execution errors."""
|
|
201
|
+
duration = time.time() - start_time
|
|
202
|
+
self.console.print(
|
|
203
|
+
f"[red]๐ฅ[/red] Test execution error after {duration:.1f}s: {error}"
|
|
204
|
+
)
|
|
205
|
+
return False
|
|
206
|
+
|
|
207
|
+
def _process_coverage_ratchet(self) -> bool:
|
|
208
|
+
"""Process coverage ratchet checks."""
|
|
209
|
+
if not self.coverage_ratchet_enabled:
|
|
210
|
+
return True
|
|
211
|
+
|
|
212
|
+
ratchet_result = self.coverage_ratchet.check_and_update_coverage()
|
|
213
|
+
return self._handle_ratchet_result(ratchet_result)
|
|
214
|
+
|
|
215
|
+
def _handle_ratchet_result(self, ratchet_result: dict[str, t.Any]) -> bool:
|
|
216
|
+
"""Handle coverage ratchet results."""
|
|
217
|
+
if ratchet_result.get("success", False):
|
|
218
|
+
if ratchet_result.get("improved", False):
|
|
219
|
+
self._handle_coverage_improvement(ratchet_result)
|
|
220
|
+
return True
|
|
221
|
+
else:
|
|
222
|
+
self.console.print(
|
|
223
|
+
f"[red]๐[/red] Coverage regression: "
|
|
224
|
+
f"{ratchet_result.get('current_coverage', 0):.2f}% < "
|
|
225
|
+
f"{ratchet_result.get('previous_coverage', 0):.2f}%"
|
|
226
|
+
)
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
def _handle_coverage_improvement(self, ratchet_result: dict[str, t.Any]) -> None:
|
|
230
|
+
"""Handle coverage improvements."""
|
|
231
|
+
improvement = ratchet_result.get("improvement", 0)
|
|
232
|
+
current = ratchet_result.get("current_coverage", 0)
|
|
233
|
+
|
|
234
|
+
self.console.print(
|
|
235
|
+
f"[green]๐[/green] Coverage improved by {improvement:.2f}% "
|
|
236
|
+
f"to {current:.2f}%"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
def _extract_failure_lines(self, output: str) -> list[str]:
|
|
240
|
+
"""Extract failure information from test output."""
|
|
241
|
+
failures = []
|
|
242
|
+
lines = output.split("\n")
|
|
243
|
+
|
|
244
|
+
for line in lines:
|
|
245
|
+
if any(
|
|
246
|
+
keyword in line for keyword in ("FAILED", "ERROR", "AssertionError")
|
|
247
|
+
):
|
|
248
|
+
failures.append(line.strip())
|
|
249
|
+
|
|
250
|
+
return failures[:10] # Limit to first 10 failures
|
|
251
|
+
|
|
252
|
+
def _get_timeout(self, options: OptionsProtocol) -> int:
|
|
253
|
+
"""Get timeout for test execution."""
|
|
254
|
+
return self.command_builder.get_test_timeout(options)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# For backward compatibility, also export the old class name
|
|
258
|
+
TestManagementImpl = TestManager
|