typing: graduate tests.test_document_* chunk out of the mypy baseline#1851
Conversation
Continues the mypy baseline drain (issue #1738), following the annotation chunk (PR #1776). Removes the 12 [mypy-opencontractserver.tests.test_document_*] ignore_errors blocks from mypy.ini, prunes the corresponding 331 lines from docs/typing/mypy_baseline.txt (5141 -> 4810), and fixes the 243 errors that surface under the pinned mypy==2.0.0 / django-stubs==6.0.5. Fixes use the established patterns from prior chunks: class-level annotations for setUpClass/setUpTestData attributes, User = get_user_model() -> direct import, the graphene self.client -> self.graphene_client rename, typed list[IndexEntryItem] / OpenContractsAnnotationPythonType literal annotations, and assert-based None narrowing. Typing self.doc as Document in test_document_index_tool also revealed a latent FieldFile.name (str | None) gap in four setUp methods (previously masked behind the attr-defined Any), now narrowed. Full surface: mypy --config-file mypy.ini opencontractserver config -> "Success: no issues found in 1242 source files". Refs #1738
|
Code review for PR 1851 - typing graduation for tests.test_document.* chunk. See detailed review below. |
Code Review:
|
The MockContext class serves as both the GraphQL info object (its .context is read) and the inner context object (its .user is read), mirroring the info.context.user access chain — so it declares both attributes even though any single instance populates only one. Add a comment so the self-referential context: 'MockContext' annotation doesn't read as spurious. (The 'Generated by Claude Code' footer was also removed from the PR body.)
Code ReviewThis is a clean, well-scoped typing PR. The approach is consistent with the established cadence (#1748, #1768, #1776), the changes are behaviour-neutral, and the baseline drain progress is real (5141 → 4810). What's solidClass-level annotations (
Minor observations (no blockers)
SummaryNo bugs, no security issues, no performance concerns. All changes are type-annotation hygiene with correct, behaviour-neutral mechanics. CI's backend job is the appropriate gate for runtime validation given the Docker constraint noted in the test plan. Ready to merge once CI is green. |
…1866) Continues the mypy baseline drain (issue #1738), following the document chunk (PR #1851). Removes the 23 [mypy-opencontractserver.tests.test_corpus_*] ignore_errors blocks from mypy.ini, prunes the corresponding 798 lines from docs/typing/mypy_baseline.txt (4810 -> 4012), and fixes the 898 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/setUp attributes, User = get_user_model() -> direct import, the graphene self.client -> self.graphene_client rename, assert ... is not None narrowing of Optional service/ORM returns, and cast() at call sites that pass intentionally-partial export TypedDict fixtures. All changes are type-level; the only behavioral-looking changes (the graphene attribute rename and the assert narrowings) are runtime-safe. Surfaced a latent production contract bug (flagged, intentionally not fixed in this test-only chunk): opencontractserver/utils/etl.py build_label_lookups declares annotation_filter_mode as the AnnotationFilterMode enum but compares it against raw string literals in some branches and enum members in others, so a str argument (what callers and the docstring use) silently skips the enum- membership branch. Recommended follow-up: normalize to a StrEnum or compare consistently. Full surface: mypy --config-file mypy.ini opencontractserver config -> "Success: no issues found in 1245 source files". Refs #1738 Co-authored-by: Claude <noreply@anthropic.com>
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 tracked in #1738 (the
#1331 → #1335 → #1447cadence). After theconfig.*tail (PR #1748), thetests.permissioning.*subpackage (PR #1768), and theannotationleaf-file chunk (PR #1776), this is the next cohesive batch from the issue'stests.*leaf-files batching plan: thedocumentdomain chunk (12 files).Removes all 12
[mypy-opencontractserver.tests.test_document_*]ignore_errorsblocks frommypy.ini, prunes the corresponding 331 lines fromdocs/typing/mypy_baseline.txt(5141 → 4810), and fixes the 243 errors that surface under the currently-pinnedmypy==2.0.0/django-stubs==6.0.5(per.pre-commit-config.yaml).After this PR, the remaining baseline is:
opencontractserver.mcp.tests.test_mcp, the othertests.*leaf-file domains (corpus / agent / extract / misc), thetests.{websocket,performance_optimizations}.*subpackages, thetests.{base,factories,diagnostic_runner,enhanced_diagnostic_runner}helpers, and the three intentionaldjango-manager-missingmodel blocks.Latent type gap revealed by typing
The issue notes graduation passes are a chance to surface real gaps hidden behind
Any. One surfaced here:test_document_index_tool.py—FieldFile.nameisstr | None. Onceself.docwas annotatedDocument(it had beenAny, masked behind theattr-definederror), the foursetUpmethods exposedself.doc.<field>.name(str | None) being passed straight intoStorage.exists()/FieldFile.save(), both of which requirestr. Narrowed via a localname = self.doc.<field>.name+assert name is not None(the file is always saved insetUpClass, so the invariant holds).Per-file fixes
test_document_index_tool.pyuser/corpus/docannotations on all 4 classes;User = get_user_model()→ direct import;entries: list[IndexEntryItem](×9) +exported: OpenContractsAnnotationPythonType(×2) literal annotations;FieldFile.namenarrowing in the 4setUps (above).test_document_versioning_graphql.pyself.client→self.graphene_clientrename (9 classes / 41.execute()); 3×assertIsNotNone(x)→assert x is not None.test_document_admin.pyTestDocumentAdmin(superuser/corpus/document/document2/embedding_*);get_user_model()→ direct import. Legit Djangoself.client = Client()left as-is.test_document_relationship_mutations.pyresult.first().relationship_type→result[0].relationship_typeafter thecount()==1guard; 1×assertIsNotNone→assert. The 32 historicalset_permissions_for_obj_to_userarg-types no longer reproduce.test_document_relationship_permissions.pytest_document_versioning.pyassert … is not None(aDocument | Noneimport result +FieldFile.namestr | None).test_document_mutations.pyself.client→self.graphene_client.test_document_analysis_row.pytest_document_uploads.pyself.client→self.graphene_client.test_document_relationships.pyself.client→self.graphene_client.test_document_queries.pyself.client→self.graphene_client.test_document_path_migration.pyuser/contexton the localMockContextmock;get_user_model()→ direct import.All changes are behaviour-neutral or behaviour-equivalent: class-level annotations and
assertvsassertIsNotNoneare runtime no-ops/equivalents;result[0]after acount()==1guard returns the same row as.first(); theself.client→self.graphene_clientrename masks Django'sTestCase.client, but the original code already shadowed it by assignment so no test relied on it (the convention matches PR #1776 /permissioning/test_permissioning.py).Test plan
mypy --config-file mypy.ini opencontractserver config→Success: no issues found in 1242 source files(the acceptance gate per Continue draining the mypy baseline established in #1331 — test suite + config tail #1738), run in a venv mirroring the.pre-commit-config.yamlpin set (mypy==2.0.0,django-stubs==6.0.5,djangorestframework-stubs==3.17.0, plus the Django runtime stack).pyupgrade --py39-plus/black==26.1.0/isort==6.0.1/flake8==7.2.0(+flake8-isort) clean on all changed files; whitespace/EOF pre-commit hooks clean.py_compilecleanly.backend.ymllinter + test jobs) — the authoritative runtime check.Refs #1738