fix(toolchain): type-annotate test helpers for the full mypy gate

make quality runs mypy over tests/ too; the toolchain test fixtures
(monkeypatch params, the fake-subprocess factories) were missing annotations.
No behavior change.
This commit is contained in:
Renn F
2026-06-22 01:59:41 +02:00
parent 78c6981089
commit 7d50405ccb
4 changed files with 29 additions and 12 deletions
+10 -5
View File
@@ -19,6 +19,7 @@ from roboco.services.gateway.choreographer import Choreographer, ChoreographerDe
from roboco.services.workspace import WorkspaceService
if TYPE_CHECKING:
from collections.abc import Callable
from pathlib import Path
# requires-python needs 3.14 but the pin says 3.13 — the resolver must ignore
@@ -55,8 +56,10 @@ def _choreographer_for(status: str | None) -> Choreographer:
return Choreographer(ChoreographerDeps(**base))
def _fake_run(captured: list[list[str]], *, collect_rc: int):
def _run(argv, **_kw) -> subprocess.CompletedProcess[str]:
def _fake_run(
captured: list[list[str]], *, collect_rc: int
) -> Callable[..., subprocess.CompletedProcess[str]]:
def _run(argv: list[str], **_kw: object) -> subprocess.CompletedProcess[str]:
captured.append(argv)
rc = collect_rc if "--collect-only" in argv else 0
return subprocess.CompletedProcess(argv, returncode=rc, stdout="", stderr="")
@@ -66,7 +69,7 @@ def _fake_run(captured: list[list[str]], *, collect_rc: int):
@pytest.mark.asyncio
async def test_broken_env_provisions_then_blocks_the_gate(
tmp_path: Path, monkeypatch
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(settings, "toolchain_match_enabled", True)
ws = _make_workspace(tmp_path)
@@ -96,7 +99,9 @@ async def test_broken_env_provisions_then_blocks_the_gate(
@pytest.mark.asyncio
async def test_ok_env_provisions_and_gate_proceeds(tmp_path: Path, monkeypatch) -> None:
async def test_ok_env_provisions_and_gate_proceeds(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(settings, "toolchain_match_enabled", True)
ws = _make_workspace(tmp_path)
svc = _service()
@@ -119,7 +124,7 @@ async def test_ok_env_provisions_and_gate_proceeds(tmp_path: Path, monkeypatch)
@pytest.mark.asyncio
async def test_flag_off_provisions_today_and_never_blocks(
tmp_path: Path, monkeypatch
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(settings, "toolchain_match_enabled", False)
ws = _make_workspace(tmp_path)
+8 -4
View File
@@ -32,7 +32,9 @@ def _make_choreographer(*, status: str | None) -> Choreographer:
@pytest.mark.asyncio
async def test_guard_blocks_when_broken_and_flag_on(monkeypatch) -> None:
async def test_guard_blocks_when_broken_and_flag_on(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(settings, "toolchain_match_enabled", True)
c = _make_choreographer(status="broken")
env = await c._toolchain_broken_guard(uuid4(), MagicMock())
@@ -43,14 +45,16 @@ async def test_guard_blocks_when_broken_and_flag_on(monkeypatch) -> None:
@pytest.mark.asyncio
async def test_guard_passes_when_ok(monkeypatch) -> None:
async def test_guard_passes_when_ok(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(settings, "toolchain_match_enabled", True)
c = _make_choreographer(status="ok")
assert await c._toolchain_broken_guard(uuid4(), MagicMock()) is None
@pytest.mark.asyncio
async def test_guard_passes_when_status_unknown_or_missing(monkeypatch) -> None:
async def test_guard_passes_when_status_unknown_or_missing(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(settings, "toolchain_match_enabled", True)
for status in ("unknown", None):
c = _make_choreographer(status=status)
@@ -58,7 +62,7 @@ async def test_guard_passes_when_status_unknown_or_missing(monkeypatch) -> None:
@pytest.mark.asyncio
async def test_guard_inert_when_flag_off(monkeypatch) -> None:
async def test_guard_inert_when_flag_off(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(settings, "toolchain_match_enabled", False)
c = _make_choreographer(status="broken")
assert await c._toolchain_broken_guard(uuid4(), MagicMock()) is None
@@ -19,6 +19,7 @@ from roboco.services.workspace import (
)
if TYPE_CHECKING:
from collections.abc import Callable
from pathlib import Path
_PY = '[project]\nname = "x"\nrequires-python = ">=3.14,<3.15"\n'
@@ -50,8 +51,10 @@ def test_detect_dep_commands_no_python_is_unchanged(tmp_path: Path) -> None:
assert commands[0][1] == ["uv", "sync", "--extra", "dev"]
def _fake_run_factory(captured: list[list[str]], *, collect_rc: int):
def _fake_run(argv, **_kw) -> subprocess.CompletedProcess[str]:
def _fake_run_factory(
captured: list[list[str]], *, collect_rc: int
) -> Callable[..., subprocess.CompletedProcess[str]]:
def _fake_run(argv: list[str], **_kw: object) -> subprocess.CompletedProcess[str]:
captured.append(argv)
rc = collect_rc if "--collect-only" in argv else 0
return subprocess.CompletedProcess(argv, returncode=rc, stdout="", stderr="")
+6 -1
View File
@@ -2,13 +2,18 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from roboco.config import Settings
if TYPE_CHECKING:
import pytest
def test_toolchain_match_disabled_by_default() -> None:
assert Settings().toolchain_match_enabled is False
def test_toolchain_match_reads_env(monkeypatch) -> None:
def test_toolchain_match_reads_env(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("ROBOCO_TOOLCHAIN_MATCH_ENABLED", "true")
assert Settings().toolchain_match_enabled is True