diff --git a/src/timmy/tools_intro/__init__.py b/src/timmy/tools_intro/__init__.py index 6f56748..abff208 100644 --- a/src/timmy/tools_intro/__init__.py +++ b/src/timmy/tools_intro/__init__.py @@ -326,6 +326,46 @@ def get_live_system_status() -> dict[str, Any]: return result +def _build_pytest_cmd(venv_python: Path, scope: str) -> list[str]: + """Build the pytest command list for the given scope.""" + cmd = [str(venv_python), "-m", "pytest", "-x", "-q", "--tb=short", "--timeout=30"] + + if scope == "fast": + cmd.extend( + [ + "--ignore=tests/functional", + "--ignore=tests/e2e", + "--ignore=tests/integrations", + "tests/", + ] + ) + elif scope == "full": + cmd.append("tests/") + else: + cmd.append(scope) + + return cmd + + +def _parse_pytest_output(output: str) -> dict[str, int]: + """Extract passed/failed/error counts from pytest output.""" + import re + + passed = failed = errors = 0 + for line in output.splitlines(): + if "passed" in line or "failed" in line or "error" in line: + nums = re.findall(r"(\d+) (passed|failed|error)", line) + for count, kind in nums: + if kind == "passed": + passed = int(count) + elif kind == "failed": + failed = int(count) + elif kind == "error": + errors = int(count) + + return {"passed": passed, "failed": failed, "errors": errors} + + def run_self_tests(scope: str = "fast", _repo_root: str | None = None) -> dict[str, Any]: """Run Timmy's own test suite and report results. @@ -349,49 +389,17 @@ def run_self_tests(scope: str = "fast", _repo_root: str | None = None) -> dict[s if not venv_python.exists(): return {"success": False, "error": f"No venv found at {venv_python}"} - cmd = [str(venv_python), "-m", "pytest", "-x", "-q", "--tb=short", "--timeout=30"] - - if scope == "fast": - # Unit tests only — skip functional/e2e/integration - cmd.extend( - [ - "--ignore=tests/functional", - "--ignore=tests/e2e", - "--ignore=tests/integrations", - "tests/", - ] - ) - elif scope == "full": - cmd.append("tests/") - else: - # Specific path - cmd.append(scope) + cmd = _build_pytest_cmd(venv_python, scope) try: result = subprocess.run(cmd, capture_output=True, text=True, timeout=120, cwd=repo) output = result.stdout + result.stderr - - # Parse pytest output for counts - passed = failed = errors = 0 - for line in output.splitlines(): - if "passed" in line or "failed" in line or "error" in line: - import re - - nums = re.findall(r"(\d+) (passed|failed|error)", line) - for count, kind in nums: - if kind == "passed": - passed = int(count) - elif kind == "failed": - failed = int(count) - elif kind == "error": - errors = int(count) + counts = _parse_pytest_output(output) return { "success": result.returncode == 0, - "passed": passed, - "failed": failed, - "errors": errors, - "total": passed + failed + errors, + **counts, + "total": counts["passed"] + counts["failed"] + counts["errors"], "return_code": result.returncode, "summary": output[-2000:] if len(output) > 2000 else output, }