[chore] remove all remaining type:ignore suppressions from tests/

Converts 115 `# type: ignore[...]` suppressions across 23 test files to
no-suppression patterns (helper-return widening to Any, local Any aliases,
cc:Any aliases, cast at narrow call sites, typed fixtures) so the hard
no-type:ignore convention holds across tests/. No test logic or assertions
changed — only mock-wiring mechanics and type annotations.

Gate: ruff check tests/ clean; mypy tests/ (538 files) clean; 176 changed-file
tests pass. Zero real suppressions remain (the 7 grep hits are 3 hygiene-
checker string-literal test inputs and 4 prose mentions in comments).
This commit is contained in:
Renn F
2026-06-28 17:00:20 +02:00
parent 4d4bf084c5
commit f826285651
23 changed files with 177 additions and 175 deletions
@@ -17,7 +17,7 @@ the session — while the happy path still adds + commits the savepoint.
from __future__ import annotations
from typing import Any
from typing import Any, cast
from uuid import uuid4
import pytest
@@ -89,7 +89,7 @@ async def test_cache_put_tolerates_concurrent_duplicate_without_poisoning() -> N
# a savepoint; _cache_put returns cleanly, the session is not poisoned, and
# no full rollback undoes the outer task-create transaction.
session = _FakeSession(duplicate=True)
svc = ConventionsService(session=session) # type: ignore[arg-type]
svc = ConventionsService(session=cast("Any", session))
await svc._cache_put(uuid4(), "deadbeef", _mapping(), "ok")
@@ -101,7 +101,7 @@ async def test_cache_put_tolerates_concurrent_duplicate_without_poisoning() -> N
@pytest.mark.asyncio
async def test_cache_put_happy_path_adds_and_releases_savepoint() -> None:
session = _FakeSession(duplicate=False)
svc = ConventionsService(session=session) # type: ignore[arg-type]
svc = ConventionsService(session=cast("Any", session))
await svc._cache_put(uuid4(), "deadbeef", _mapping(), "ok")
@@ -4,7 +4,7 @@ from __future__ import annotations
import subprocess
from types import SimpleNamespace
from typing import TYPE_CHECKING, cast
from typing import TYPE_CHECKING, Any, cast
from roboco.services.conventions import ConventionsService
@@ -33,7 +33,7 @@ def _git_repo(root: Path) -> str:
def _svc() -> ConventionsService:
return ConventionsService(session=None) # type: ignore[arg-type]
return ConventionsService(session=cast("Any", None))
def test_resolve_reads_clone_head_and_backfills(tmp_path: Path) -> None:
@@ -18,7 +18,7 @@ import pytest
from roboco.services.git import GitService
def _git_service() -> GitService:
def _git_service() -> Any:
return GitService.__new__(GitService)
@@ -26,8 +26,8 @@ def _git_service() -> GitService:
async def test_resolve_diff_base_uses_parent_when_pushed() -> None:
"""When origin/<parent> exists, use it (normal case)."""
svc = _git_service()
svc._run_git = AsyncMock() # type: ignore[method-assign]
svc._ref_exists = AsyncMock(return_value=True) # type: ignore[method-assign]
svc._run_git = AsyncMock()
svc._ref_exists = AsyncMock(return_value=True)
ws = Path("/tmp/ws")
base = await svc._resolve_diff_base(
@@ -42,12 +42,10 @@ async def test_resolve_diff_base_falls_back_when_parent_absent() -> None:
"""When origin/<parent> does NOT exist (cell-PM branch never pushed),
fall back to the repo default branch via origin/HEAD."""
svc = _git_service()
svc._run_git = AsyncMock() # type: ignore[method-assign]
svc._run_git = AsyncMock()
# parent ref absent → _ref_exists False for the parent check.
svc._ref_exists = AsyncMock(return_value=False) # type: ignore[method-assign]
svc._default_branch_ref = AsyncMock( # type: ignore[method-assign]
return_value="origin/master"
)
svc._ref_exists = AsyncMock(return_value=False)
svc._default_branch_ref = AsyncMock(return_value="origin/master")
ws = Path("/tmp/ws")
base = await svc._resolve_diff_base(
@@ -84,7 +82,7 @@ async def test_default_branch_ref_fallback_when_no_head() -> None:
# symbolic-ref fails; fetches succeed but ref never verifies.
return type("R", (), {"returncode": 1, "stdout": ""})()
svc._ref_exists = AsyncMock(return_value=False) # type: ignore[method-assign]
svc._ref_exists = AsyncMock(return_value=False)
with patch.object(svc, "_run_git", new=fake_run):
ref = await svc._default_branch_ref(Path("/tmp/ws"))
assert ref == "origin/master"
@@ -107,8 +105,8 @@ _BR = "feature/backend/root1234--cellpm56--dev78901"
async def test_resolve_head_ref_prefers_local_branch_in_dev_clone() -> None:
"""Dev's own clone has the local branch — use it unchanged."""
svc = _git_service()
svc._run_git = AsyncMock() # type: ignore[method-assign]
svc._ref_exists = AsyncMock(return_value=True) # type: ignore[method-assign]
svc._run_git = AsyncMock()
svc._ref_exists = AsyncMock(return_value=True)
head = await svc._resolve_head_ref(Path("/tmp/ws"), _BR)
assert head == _BR
@@ -119,7 +117,7 @@ async def test_resolve_head_ref_falls_back_to_origin_in_foreign_clone() -> None:
"""QA/doc/PM clone has no local branch but origin/<branch> exists
(open_pr pushed it) — diff must target origin/<branch>."""
svc = _git_service()
svc._run_git = AsyncMock() # type: ignore[method-assign]
svc._run_git = AsyncMock()
async def ref_exists(_ws: Any, ref: str) -> bool:
# local branch absent; only the remote-tracking ref resolves.
@@ -141,7 +139,7 @@ async def test_resolve_head_ref_fetches_branch_before_resolving() -> None:
calls.append(args)
return type("R", (), {"returncode": 0, "stdout": ""})()
svc._ref_exists = AsyncMock(return_value=True) # type: ignore[method-assign]
svc._ref_exists = AsyncMock(return_value=True)
with patch.object(svc, "_run_git", new=fake_run):
await svc._resolve_head_ref(Path("/tmp/ws"), _BR)
assert ["fetch", "origin", _BR] in calls
@@ -153,18 +151,10 @@ async def test_diff_targets_origin_head_in_foreign_clone() -> None:
base...origin/<branch>, not base...<bare-local-branch> (which is
unresolvable there and silently produced an empty diff)."""
svc = _git_service()
svc._workspace_for_branch = AsyncMock( # type: ignore[method-assign]
return_value=Path("/tmp/qa-ws")
)
svc._resolve_diff_base = AsyncMock( # type: ignore[method-assign]
return_value="origin/master"
)
svc._resolve_head_ref = AsyncMock( # type: ignore[method-assign]
return_value=f"origin/{_BR}"
)
svc._token_for_branch = AsyncMock( # type: ignore[method-assign]
return_value="tok"
)
svc._workspace_for_branch = AsyncMock(return_value=Path("/tmp/qa-ws"))
svc._resolve_diff_base = AsyncMock(return_value="origin/master")
svc._resolve_head_ref = AsyncMock(return_value=f"origin/{_BR}")
svc._token_for_branch = AsyncMock(return_value="tok")
captured: list[list[str]] = []
async def fake_run(_ws: Any, args: list[str], **_kw: Any) -> Any:
@@ -187,18 +177,10 @@ async def test_diff_targets_origin_head_in_foreign_clone() -> None:
async def test_list_changed_files_targets_origin_head_in_foreign_clone() -> None:
"""Same fix on the files_changed path (#154 evidence)."""
svc = _git_service()
svc._workspace_for_branch = AsyncMock( # type: ignore[method-assign]
return_value=Path("/tmp/qa-ws")
)
svc._resolve_diff_base = AsyncMock( # type: ignore[method-assign]
return_value="origin/master"
)
svc._resolve_head_ref = AsyncMock( # type: ignore[method-assign]
return_value=f"origin/{_BR}"
)
svc._token_for_branch = AsyncMock( # type: ignore[method-assign]
return_value="tok"
)
svc._workspace_for_branch = AsyncMock(return_value=Path("/tmp/qa-ws"))
svc._resolve_diff_base = AsyncMock(return_value="origin/master")
svc._resolve_head_ref = AsyncMock(return_value=f"origin/{_BR}")
svc._token_for_branch = AsyncMock(return_value="tok")
captured: list[list[str]] = []
async def fake_run(_ws: Any, args: list[str], **_kw: Any) -> Any:
@@ -219,18 +201,10 @@ async def test_diff_honours_explicit_base_with_resolved_head() -> None:
"""The incremental dev path (base=HEAD~1) still works: explicit base
is preserved, head still goes through _resolve_head_ref."""
svc = _git_service()
svc._workspace_for_branch = AsyncMock( # type: ignore[method-assign]
return_value=Path("/tmp/dev-ws")
)
svc._resolve_diff_base = AsyncMock( # type: ignore[method-assign]
return_value="SHOULD_NOT_BE_USED"
)
svc._resolve_head_ref = AsyncMock( # type: ignore[method-assign]
return_value=_BR
)
svc._token_for_branch = AsyncMock( # type: ignore[method-assign]
return_value=None
)
svc._workspace_for_branch = AsyncMock(return_value=Path("/tmp/dev-ws"))
svc._resolve_diff_base = AsyncMock(return_value="SHOULD_NOT_BE_USED")
svc._resolve_head_ref = AsyncMock(return_value=_BR)
svc._token_for_branch = AsyncMock(return_value=None)
captured: list[list[str]] = []
async def fake_run(_ws: Any, args: list[str], **_kw: Any) -> Any:
@@ -266,10 +240,8 @@ async def test_resolve_diff_base_refetches_default_branch_with_token() -> None:
return type("R", (), {"returncode": 0, "stdout": ""})()
# parent ref never exists → fall back to default branch.
svc._ref_exists = AsyncMock(return_value=False) # type: ignore[method-assign]
svc._default_branch_ref = AsyncMock( # type: ignore[method-assign]
return_value="origin/master"
)
svc._ref_exists = AsyncMock(return_value=False)
svc._default_branch_ref = AsyncMock(return_value="origin/master")
with patch.object(svc, "_run_git", new=fake_run):
base = await svc._resolve_diff_base(Path("/tmp/ws"), _BR, token="tok")
@@ -291,7 +263,7 @@ async def test_resolve_head_ref_fetch_is_authenticated() -> None:
seen.append((args, kw.get("token")))
return type("R", (), {"returncode": 0, "stdout": ""})()
svc._ref_exists = AsyncMock(return_value=True) # type: ignore[method-assign]
svc._ref_exists = AsyncMock(return_value=True)
with patch.object(svc, "_run_git", new=fake_run):
await svc._resolve_head_ref(Path("/tmp/ws"), _BR, token="tok")
assert (["fetch", "origin", _BR], "tok") in seen
@@ -302,5 +274,5 @@ async def test_token_for_branch_is_best_effort_none() -> None:
"""Unresolvable branch/project must yield None (degrade to unauth),
never raise inside the evidence-assembly path."""
svc = _git_service()
svc._task_for_branch = AsyncMock(return_value=None) # type: ignore[method-assign]
svc._task_for_branch = AsyncMock(return_value=None)
assert await svc._token_for_branch(_BR) is None
@@ -23,8 +23,8 @@ _BASE = "feature/backend/parent12345"
_HEAD = "feature/backend/abc12345"
def _git_service() -> GitService:
svc = GitService.__new__(GitService)
def _git_service() -> Any:
svc: Any = GitService.__new__(GitService)
svc.log = MagicMock()
return svc
@@ -45,14 +45,14 @@ def _project() -> Any:
return MagicMock(slug="roboco")
async def _wire(svc: GitService, *, rev_list_stdout: str) -> AsyncMock:
async def _wire(svc: Any, *, rev_list_stdout: str) -> AsyncMock:
"""Stub the workspace/token resolution + _run_git; return the run mock."""
svc._project_for_task = AsyncMock(return_value=_project()) # type: ignore[method-assign]
svc._resolve_workspace_agent_id = MagicMock(return_value=uuid4()) # type: ignore[method-assign]
svc.get_workspace = AsyncMock(return_value=_WORKSPACE) # type: ignore[method-assign]
svc._get_project_token_or_raise = AsyncMock(return_value=_TOKEN) # type: ignore[method-assign]
svc._project_for_task = AsyncMock(return_value=_project())
svc._resolve_workspace_agent_id = MagicMock(return_value=uuid4())
svc.get_workspace = AsyncMock(return_value=_WORKSPACE)
svc._get_project_token_or_raise = AsyncMock(return_value=_TOKEN)
run = AsyncMock(side_effect=[_result(), _result(stdout=rev_list_stdout)])
svc._run_git = run # type: ignore[method-assign]
svc._run_git = run
return run
@@ -116,7 +116,7 @@ async def test_is_behind_base_requires_branch_name() -> None:
@pytest.mark.asyncio
async def test_is_behind_base_raises_when_project_missing() -> None:
svc = _git_service()
svc._project_for_task = AsyncMock(return_value=None) # type: ignore[method-assign]
svc._project_for_task = AsyncMock(return_value=None)
with pytest.raises(NotFoundError):
await svc.is_behind_base(_task(), base_branch=_BASE)
@@ -26,10 +26,10 @@ def _link(session_id: object, relationship_type: str) -> MagicMock:
@pytest.mark.asyncio
async def test_propagate_links_every_parent_session_to_subtask() -> None:
"""Every link on the parent gets re-attached to the new subtask."""
svc = MessagingService.__new__(MessagingService)
svc: Any = MessagingService.__new__(MessagingService)
parent_session = uuid4()
review_session = uuid4()
svc.get_sessions_for_task = AsyncMock( # type: ignore[method-assign]
svc.get_sessions_for_task = AsyncMock(
return_value=[
_link(parent_session, "discussion"),
_link(review_session, "review"),
@@ -67,9 +67,9 @@ async def test_propagate_links_every_parent_session_to_subtask() -> None:
@pytest.mark.asyncio
async def test_propagate_no_parent_sessions_returns_empty() -> None:
"""When the parent has no session links, propagation is a no-op."""
svc = MessagingService.__new__(MessagingService)
svc.get_sessions_for_task = AsyncMock(return_value=[]) # type: ignore[method-assign]
svc.link_session_to_task = AsyncMock() # type: ignore[method-assign]
svc: Any = MessagingService.__new__(MessagingService)
svc.get_sessions_for_task = AsyncMock(return_value=[])
svc.link_session_to_task = AsyncMock()
out = await svc.propagate_sessions_to_subtask(uuid4(), uuid4(), uuid4())
assert out == []
@@ -80,8 +80,8 @@ async def test_propagate_no_parent_sessions_returns_empty() -> None:
async def test_propagate_unknown_relationship_type_defaults_to_discussion() -> None:
"""Garbage relationship_type on the parent link doesn't crash; it
defaults to DISCUSSION so the subtask is still linked."""
svc = MessagingService.__new__(MessagingService)
svc.get_sessions_for_task = AsyncMock( # type: ignore[method-assign]
svc: Any = MessagingService.__new__(MessagingService)
svc.get_sessions_for_task = AsyncMock(
return_value=[_link(uuid4(), "definitely-not-a-real-type")]
)
calls: list[dict[str, Any]] = []
@@ -22,9 +22,9 @@ _PCT_NONE = 0
_PCT_FALLBACK = 42
def _svc_with_task(task: Any) -> TaskService:
svc = TaskService.__new__(TaskService)
svc.get = AsyncMock(return_value=task) # type: ignore[method-assign]
def _svc_with_task(task: Any) -> Any:
svc: Any = TaskService.__new__(TaskService)
svc.get = AsyncMock(return_value=task)
svc.session = MagicMock()
svc.session.flush = AsyncMock()
return svc
@@ -119,6 +119,6 @@ async def test_no_checklist_falls_back_to_supplied_percentage() -> None:
@pytest.mark.asyncio
async def test_missing_task_returns_none() -> None:
svc = TaskService.__new__(TaskService)
svc.get = AsyncMock(return_value=None) # type: ignore[method-assign]
svc: Any = TaskService.__new__(TaskService)
svc.get = AsyncMock(return_value=None)
assert await svc.record_plan_progress(uuid4(), uuid4(), "x") is None
+3 -1
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
from typing import Any, cast
import pytest
from roboco.services.base import (
BaseService,
@@ -120,7 +122,7 @@ def test_base_service_binds_session_and_logger() -> None:
service_name = "x"
fake_session = object()
svc = _Svc(fake_session) # type: ignore[arg-type]
svc = _Svc(cast("Any", fake_session))
assert svc.session is fake_session
assert svc.log is not None