You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -38,6 +38,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
38
38
-`.github/workflows/backend.yml`: `Run mypy` step added to the `linter` job; the preceding `pip install -r requirements/local.txt` step satisfies the django-stubs plugin.
39
39
-`docs/typing/README.md`: how to run locally / via pre-commit / in the test container, plus the per-file graduation workflow.
40
40
-`docs/typing/mypy_baseline.txt`: frozen error list (sorted for stable diffs) so follow-up issues can measure progress.
41
+
-**Mypy: typed the auth, users, and notifications packages** (Issue #1333, follow-up to #1331): Brought `config/admin_auth`, `config/graphql_api_token_auth`, `opencontractserver/users`, and `opencontractserver/notifications` to full return-annotation coverage and graduated them out of the mypy baseline. These packages sit on hot paths for authentication, token verification, session handling, and notification dispatch; typing them documents invariants that used to live only in `CLAUDE.md`.
42
+
- Signal handlers (`opencontractserver/users/signals.py`, `opencontractserver/notifications/signals.py`) now declare `sender: type[Model]`, `instance: Model`, `created: bool`, `**kwargs: Any`, and `-> None` so drive-by edits can't silently change the signal contract.
43
+
-`opencontractserver/notifications/__init__.py` gained a module-level docstring calling out that the app deliberately diverges from `AnnotatePermissionsForReadMixin` — a single `recipient` FK is the authoritative visibility gate. The design note in `CLAUDE.md` is referenced so changes to one file flag the other.
44
+
-`mypy.ini`: dropped `[mypy-config.admin_auth.*]`, `[mypy-config.graphql_api_token_auth.backends]`, and `[mypy-opencontractserver.users.models]``ignore_errors` sections. Added a narrow `disable_error_code = django-manager-missing` on `opencontractserver.users.models` only, documented inline: `django-tree-queries`' `as_manager(with_tree_fields=True)` pattern used by `Corpus`, `CorpusFolder`, and `DocumentPath` creates manager classes at runtime that the `mypy_django_plugin` can't introspect, so reverse `_set` accessors on `User` can't resolve — a known plugin limitation, not a code error. Graduating those three models with explicit manager typing will let us delete the disable.
45
+
-`docs/typing/mypy_baseline.txt`: pruned all 20 entries for the graduated modules.
46
+
- Bug fixes uncovered by typing:
47
+
-`config/graphql_api_token_auth/backends.py`: `ApiKeyBackend.authenticate_header` referenced `self.keyword` but the attribute was never declared. DRF calls this on 401 responses to build the `WWW-Authenticate` header, so an unauthenticated request would have hit `AttributeError` at response time. Added `keyword: str = "Token"` as a class attribute.
48
+
-`opencontractserver/notifications/signals.py`: `create_moderation_notification` dereferenced `action.moderator.username` unconditionally, but the `ModerationAction.moderator` FK permits `NULL`. A moderation action created without a moderator would crash the signal handler (and therefore the originating save). Added an explicit early return with a debug log when `action.moderator is None`.
0 commit comments