typing: graduate tests.test_agent* chunk out of the mypy baseline#1877
Conversation
Continues the mypy baseline drain (issue #1738), following the corpus chunk (PR #1866). Removes the 9 [mypy-opencontractserver.tests.test_agent*] ignore_errors blocks from mypy.ini, prunes the corresponding 364 lines from docs/typing/mypy_baseline.txt (4012 -> 3648), and fixes the 338 errors that surface under the pinned mypy==2.0.0 / django-stubs==6.0.5 (also verified clean under CI's mypy==2.1.0). Fixes use the established patterns from prior chunks: class-level annotations for setUpTestData/setUpClass attributes, User = get_user_model() -> direct import, the graphene self.client -> self.graphene_client rename (test_agents.py), list[ToolType] annotations to satisfy list invariance, assert ... is not None narrowing of Optional returns, and error-code-scoped type: ignore for deliberately-invalid test inputs. All changes are type-level and behaviour-neutral or behaviour-equivalent. Two test-quality findings surfaced behind the mocks: - test_agent_api.py passed a non-existent embedder_path= kwarg to embeddings.generate (the public param is embedder); corrected to embedder=, keeping the mocked test green while aligning it with the real API. - CoreAgent.stream_chat is a legacy wrapper on the concrete base, absent from the modern CoreAgent protocol and never called in production; the two test call sites are scoped with type: ignore[attr-defined] rather than re-blessing it into the protocol. Full surface: mypy --config-file mypy.ini opencontractserver config -> "Success: no issues found in 1247 source files". Refs #1738
The mypy-baseline graduation carried a blanket embedder_path -> embedder rename into TestVectorStoreAPI::test_vector_store_with_all_options, but VectorStoreAPI.create's public parameter is genuinely named embedder_path (forwarded straight to UnifiedVectorStoreFactory.create_vector_store). Because create has a **kwargs catch-all, the wrong embedder= kwarg was silently absorbed while embedder_path defaulted to None, so the assert_called_once_with(embedder=...) no longer matched the actual create_vector_store(embedder_path=None, ..., embedder=...) call. Restore embedder_path on both the call and the assertion. Document the correction in CHANGELOG.
Code ReviewThis is a clean, well-executed typing graduation PR. All changes are confined to test files, config ( Positives
Minor Concerns / Follow-up Candidates
The PR correctly scopes these as ClassVar overrides in The
The inline SummaryNo blocking issues. The real-value find is the |
Continues the mypy baseline drain (issue Open-Source-Legal#1738, the Open-Source-Legal#1331 -> Open-Source-Legal#1335 -> Open-Source-Legal#1447 cadence). After the config tail (Open-Source-Legal#1748), tests.permissioning.* (Open-Source-Legal#1768), and the annotation (Open-Source-Legal#1776) / document (Open-Source-Legal#1851) / corpus (Open-Source-Legal#1866) / agent (Open-Source-Legal#1877) leaf-file chunks, this is the next cohesive batch from the issue's tests.* batching plan: the extract domain. Removes the 6 [mypy-opencontractserver.tests.test_*] ignore_errors blocks for the structured-data-extraction feature -- Extracts plus their Fieldsets/Columns, Datacells, and metadata columns (all in opencontractserver/extracts/models.py): test_extract_mutations, test_extract_queries, test_extract_tasks, test_datacell_mutations, test_column_mutations, test_metadata_columns_graphql. Prunes the corresponding 57 lines from docs/typing/mypy_baseline.txt (3648 -> 3591) and fixes the 42 errors that surface. Every surfaced error was the same: a graphene.test.Client assigned to self.client shadows django.test.TestCase.client (which has no .execute()). Renamed self.client -> self.graphene_client in the 5 GraphQL test modules -- a behaviour-equivalent rename, since the assignment already shadowed the Django client at runtime and every read was .execute(). test_extract_tasks needed no code change: its historical set_permissions_for_obj_to_user arg-type errors no longer reproduce under django-stubs==6.0.5. Full project surface (mypy --config-file mypy.ini opencontractserver config) stays clean under both the pre-commit pin (mypy==2.0.0) and CI's pin (mypy==2.1.0). Refs Open-Source-Legal#1738
Summary
Continues the mypy baseline drain (issue #1738, the
#1331 → #1335 → #1447cadence), graduating theagenttest domain — the next cohesive chunk in the issue'stests.*leaf-files batching plan (corpus / document / annotation / agent / extract / misc), following thecorpuschunk in #1866,documentin #1851, andannotationin #1776.[mypy-opencontractserver.tests.test_agent*]ignore_errorsblocks frommypy.ini(test_agent_action_result,test_agent_action_result_admin,test_agent_api,test_agent_factory,test_agent_framework_api,test_agent_memory,test_agent_tasks,test_agentic_highlighter_task,test_agents).docs/typing/mypy_baseline.txt(4012 → 3648).Full surface passes under both pinned toolchains:
mypy==2.0.0/django-stubs==6.0.5(pre-commit.pre-commit-config.yaml) →Success: no issues found in 1247 source filesmypy==2.1.0/django-stubs==6.0.5(CIrequirements/local.txt) →SuccessHow
All changes are type-level and behaviour-neutral or behaviour-equivalent. Patterns are the established ones from prior chunks:
setUpTestData/setUpClassattributes mypy can't follow into classmethod bodies (the typing: graduate opencontractserver.discovery.tests.test_discovery_views from mypy baseline #1479 fix) — the bulk of the 338.test_agent_framework_api.pyhas a single sharedTestAPISetupbase (11 fixtures) inherited by 3 subclasses, so one annotation block covers all four.User = get_user_model()→from opencontractserver.users.models import Userso the name is usable as a type (and the now-unusedget_user_modelimport removed).test_agents.py): agraphene.test.Clientassigned toself.clientshadows the inheriteddjango.test.TestCase.client, which has no.execute(). (test_agent_action_result_admin.pywas deliberately not renamed — it uses the realdjango.test.Clientfor admin GET requests.)list[ToolType]annotations (test_agent_api.py,test_agent_factory.py):list[str]/ mixed tool literals passed to_resolve_tools/create_document_agent(both takelist[ToolType]) annotated so list invariance is satisfied.assertIsNotNone(x)→assert x is not None(preserves the assertion while narrowing) forToolRegistryEntry/CoreToolregistry returns,_FakeConfig.system_prompt(Optional[str]), andAgentActionResult.duration_seconds(float | None).# type: ignores (no blanket ignores;warn_unused_ignores=Truekeeps them honest): a deliberately-NoneAdminSite; the deliberately-invalidframework="invalid_framework_name"string that exercises theValueErrorpath; a deliberately-invalid["summarize", 123, None]tool list that exercises the skip-and-warn path; the per-instance override of the baseClassVarcorpus/docsfixtures intest_agentic_highlighter_task.py; and the legacystream_chatwrapper (see below).The issue frames graduation as a chance to audit for bugs hidden behind auto-attribute mocks. Two surfaced:
test_agent_api.py::test_contextual_embedding_generationpassed a non-existentembedder_path=kwarg toembeddings.generate. The publicEmbeddingAPI.generateparameter isembedder(noembedder_path, no**kwargs); the call only "worked" becausegeneratewas mocked, hiding the wrong kwarg name. Corrected the call (and itsassert_called_once_with) toembedder=— keeps the test green and self-consistent while aligning it with the real public API (mypy now confirmsembedderis the correct param).CoreAgent.stream_chatis a legacy compatibility wrapper that lives on the concreteCoreAgentBasebut is deliberately absent from the modernCoreAgentprotocol (which exposesstream). It is never called in production — onlytest_agent_api.pyandtest_agent_framework_api.pyexercise it, via mocks that replace it wholesale. Left the protocol as-is (the omission looks intentional, unlike theconfigattribute completed in typing: graduate tests.permissioning.* subpackage out of the mypy baseline #1768) and scoped the two test calls with# type: ignore[attr-defined]. Follow-up candidate: either foldstream_chatinto the protocol or remove the now-effectively-dead wrapper.Acceptance (per issue #1738)
mypy.iniagent blocks removed (9).docs/typing/mypy_baseline.txtpruned (364 lines).mypypasses on the full project surface.embedder_path→embedderrename keeps the mocked test green and self-consistent).black==26.1.0/isort==6.0.1/flake8==7.2.0(+flake8-isort) /pyupgrade --py39-plusclean on all changed files;py_compileclean.Test plan
mypy --config-file mypy.ini opencontractserver config→Success: no issues found in 1247 source files, under a venv mirroring the.pre-commit-config.yamlpin set (mypy==2.0.0,django-stubs==6.0.5, plus the Django runtime stack), and again under CI'smypy==2.1.0.black/isort/flake8/pyupgradeclean; whitespace/EOF clean.backend.ymllinter + test jobs) — the authoritative runtime check.Refs #1738