-
-
Notifications
You must be signed in to change notification settings - Fork 553
Use newer syntax and enable more mypy configuration options #3203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 11 commits
1045043
ade7d6b
2b13922
2c4d7c9
3bdd318
b8de5d7
de65b44
b40c7fe
3b3bef4
b0fed11
f1a9c28
e1fb22a
a45df83
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import typing | ||
|
|
||
| if typing.TYPE_CHECKING: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
| if TYPE_CHECKING: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
| if TYPE_CHECKING: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import Any, Protocol | ||
|
|
||
| from typing_extensions import override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import Any | ||
|
|
||
| from django_stubs_ext import ValuesQuerySet | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import configparser | ||
| import os | ||
| import sys | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,21 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import os | ||
| import sys | ||
| from collections import defaultdict | ||
| from collections.abc import Iterable, Iterator, Mapping, Sequence | ||
| from contextlib import contextmanager | ||
| from functools import cached_property | ||
| from typing import TYPE_CHECKING, Any, Literal, Union | ||
| from typing import TYPE_CHECKING, Any, Literal | ||
|
|
||
| from django.core.exceptions import FieldDoesNotExist, FieldError | ||
| from django.db import models | ||
| from django.db.models.base import Model | ||
| from django.db.models.constants import LOOKUP_SEP | ||
| from django.db.models.expressions import Expression | ||
| from django.db.models.fields import AutoField, CharField, Field | ||
| from django.db.models.fields.related import ForeignKey, RelatedField | ||
| from django.db.models.fields.reverse_related import ForeignObjectRel | ||
| from django.db.models.lookups import Exact | ||
| from django.db.models.sql.query import Query | ||
| from mypy.checker import TypeChecker | ||
| from mypy.nodes import TypeInfo | ||
| from mypy.plugin import MethodContext | ||
| from mypy.typeanal import make_optional_type | ||
| from mypy.types import AnyType, Instance, ProperType, TypeOfAny, UnionType, get_proper_type | ||
| from mypy.types import Type as MypyType | ||
|
|
@@ -36,9 +33,15 @@ class ArrayField: # type: ignore[no-redef] | |
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| from collections.abc import Iterable, Iterator, Mapping, Sequence | ||
|
|
||
| from django.apps.registry import Apps | ||
| from django.conf import LazySettings | ||
| from django.db.models.expressions import Expression | ||
| from django.db.models.options import _AnyField | ||
| from mypy.checker import TypeChecker | ||
| from mypy.nodes import TypeInfo | ||
| from mypy.plugin import MethodContext | ||
|
|
||
|
|
||
| @contextmanager | ||
|
|
@@ -52,7 +55,7 @@ def temp_environ() -> Iterator[None]: | |
| os.environ.update(environ) | ||
|
|
||
|
|
||
| def initialize_django(settings_module: str) -> tuple["Apps", "LazySettings"]: | ||
| def initialize_django(settings_module: str) -> tuple[Apps, LazySettings]: | ||
| with temp_environ(): | ||
| os.environ["DJANGO_SETTINGS_MODULE"] = settings_module | ||
|
|
||
|
|
@@ -133,17 +136,17 @@ def get_model_class_by_fullname(self, fullname: str) -> type[Model] | None: | |
| module, _, model_cls_name = fullname.rpartition(".") | ||
| return self.model_modules.get(module, {}).get(model_cls_name) | ||
|
|
||
| def get_model_fields(self, model_cls: type[Model]) -> Iterator["Field[Any, Any]"]: | ||
| def get_model_fields(self, model_cls: type[Model]) -> Iterator[Field[Any, Any]]: | ||
| for field in model_cls._meta.get_fields(): | ||
| if isinstance(field, Field): | ||
| yield field | ||
|
|
||
| def get_model_foreign_keys(self, model_cls: type[Model]) -> Iterator["ForeignKey[Any, Any]"]: | ||
| def get_model_foreign_keys(self, model_cls: type[Model]) -> Iterator[ForeignKey[Any, Any]]: | ||
| for field in model_cls._meta.get_fields(): | ||
| if isinstance(field, ForeignKey): | ||
| yield field | ||
|
|
||
| def get_model_related_fields(self, model_cls: type[Model]) -> Iterator["RelatedField[Any, Any]"]: | ||
| def get_model_related_fields(self, model_cls: type[Model]) -> Iterator[RelatedField[Any, Any]]: | ||
| """Get model forward relations""" | ||
| for field in model_cls._meta.get_fields(): | ||
| if isinstance(field, RelatedField): | ||
|
|
@@ -155,9 +158,7 @@ def get_model_relations(self, model_cls: type[Model]) -> Iterator[ForeignObjectR | |
| if isinstance(field, ForeignObjectRel): | ||
| yield field | ||
|
|
||
| def get_field_lookup_exact_type( | ||
| self, api: TypeChecker, field: Union["Field[Any, Any]", ForeignObjectRel] | ||
| ) -> MypyType: | ||
| def get_field_lookup_exact_type(self, api: TypeChecker, field: Field[Any, Any] | ForeignObjectRel) -> MypyType: | ||
| if isinstance(field, RelatedField | ForeignObjectRel): | ||
| related_model_cls = self.get_field_related_model_cls(field) | ||
| rel_model_info = helpers.lookup_class_typeinfo(api, related_model_cls) | ||
|
|
@@ -176,8 +177,8 @@ def get_field_lookup_exact_type( | |
| return helpers.get_private_descriptor_type(field_info, "_pyi_lookup_exact_type", is_nullable=field.null) | ||
|
|
||
| def get_related_target_field( | ||
| self, related_model_cls: type[Model], field: "ForeignKey[Any, Any]" | ||
| ) -> "Field[Any, Any] | None": | ||
| self, related_model_cls: type[Model], field: ForeignKey[Any, Any] | ||
| ) -> Field[Any, Any] | None: | ||
| # ForeignKey only supports one `to_fields` item (ForeignObject supports many) | ||
| assert len(field.to_fields) == 1 | ||
| to_field_name = field.to_fields[0] | ||
|
|
@@ -188,7 +189,7 @@ def get_related_target_field( | |
| return rel_field | ||
| return self.get_primary_key_field(related_model_cls) | ||
|
|
||
| def get_primary_key_field(self, model_cls: type[Model]) -> "Field[Any, Any]": | ||
| def get_primary_key_field(self, model_cls: type[Model]) -> Field[Any, Any]: | ||
| for field in model_cls._meta.get_fields(): | ||
| if isinstance(field, Field): | ||
| if field.primary_key: | ||
|
|
@@ -289,7 +290,7 @@ def model_class_fullnames_by_label(self) -> Mapping[str, str]: | |
| if klass is not models.Model | ||
| } | ||
|
|
||
| def get_field_nullability(self, field: Union["Field[Any, Any]", ForeignObjectRel], method: str | None) -> bool: | ||
| def get_field_nullability(self, field: Field[Any, Any] | ForeignObjectRel, method: str | None) -> bool: | ||
| if method in ("values", "values_list"): | ||
| return field.null | ||
|
|
||
|
|
@@ -307,7 +308,7 @@ def get_field_nullability(self, field: Union["Field[Any, Any]", ForeignObjectRel | |
| return nullable | ||
|
|
||
| def get_field_set_type( | ||
| self, api: TypeChecker, field: Union["Field[Any, Any]", ForeignObjectRel], *, method: str | ||
| self, api: TypeChecker, field: Field[Any, Any] | ForeignObjectRel, *, method: str | ||
| ) -> MypyType: | ||
| """Get a type of __set__ for this specific Django field.""" | ||
| target_field = field | ||
|
|
@@ -335,7 +336,7 @@ def get_field_get_type( | |
| self, | ||
| api: TypeChecker, | ||
| model_info: TypeInfo | None, | ||
| field: Union["Field[Any, Any]", ForeignObjectRel], | ||
| field: Field[Any, Any] | ForeignObjectRel, | ||
| *, | ||
| method: str, | ||
| ) -> MypyType: | ||
|
|
@@ -365,15 +366,12 @@ def get_field_get_type( | |
| return Instance(model_info, []) | ||
| return helpers.get_private_descriptor_type(field_info, "_pyi_private_get_type", is_nullable=is_nullable) | ||
|
|
||
| def get_field_related_model_cls(self, field: Union["RelatedField[Any, Any]", ForeignObjectRel]) -> type[Model]: | ||
| def get_field_related_model_cls(self, field: RelatedField[Any, Any] | ForeignObjectRel) -> type[Model]: | ||
| if isinstance(field, RelatedField): | ||
| related_model_cls = field.remote_field.model | ||
| else: | ||
| related_model_cls = field.field.model | ||
|
|
||
| if related_model_cls is None: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. Probably. This likely indicates that the stubs are wrong somewhere. |
||
| raise UnregisteredModelError | ||
|
|
||
| if isinstance(related_model_cls, str): | ||
| if related_model_cls == "self": # type: ignore[unreachable] | ||
| # same model | ||
|
|
@@ -394,7 +392,7 @@ def get_field_related_model_cls(self, field: Union["RelatedField[Any, Any]", For | |
|
|
||
| def _resolve_field_from_parts( | ||
| self, field_parts: Iterable[str], model_cls: type[Model] | ||
| ) -> tuple[Union["Field[Any, Any]", ForeignObjectRel], type[Model]]: | ||
| ) -> tuple[Field[Any, Any] | ForeignObjectRel, type[Model]]: | ||
| currently_observed_model = model_cls | ||
| field: _AnyField | None = None | ||
| for field_part in field_parts: | ||
|
|
@@ -420,7 +418,7 @@ def solve_lookup_type( | |
| self, model_cls: type[Model], lookup: str | ||
| ) -> tuple[Sequence[str], Sequence[str], Expression | Literal[False]] | None: | ||
| query = Query(model_cls) | ||
| if (lookup == "pk" or lookup.startswith("pk__")) and query.get_meta().pk is None: | ||
| if (lookup == "pk" or lookup.startswith("pk__")) and query.get_meta().pk is None: # type: ignore[comparison-overlap] | ||
| # Primary key lookup when no primary key field is found, model is presumably | ||
| # abstract and we can't say anything about 'pk'. | ||
| return None | ||
|
Comment on lines
+421
to
424
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is a little tricky because of the change in e3f5b3d. I decided to punt on removing this block for now - we can follow up later. |
||
|
|
@@ -452,7 +450,7 @@ def solve_lookup_type( | |
|
|
||
| def resolve_lookup_into_field( | ||
| self, model_cls: type[Model], lookup: str | ||
| ) -> tuple[Union["Field[Any, Any]", ForeignObjectRel, None], type[Model]]: | ||
| ) -> tuple[Field[Any, Any] | ForeignObjectRel | None, type[Model]]: | ||
| solved_lookup = self.solve_lookup_type(model_cls, lookup) | ||
| if solved_lookup is None: | ||
| return None, model_cls | ||
|
|
@@ -462,7 +460,7 @@ def resolve_lookup_into_field( | |
| return self._resolve_field_from_parts(field_parts, model_cls) | ||
|
|
||
| def _resolve_lookup_type_from_lookup_class( | ||
| self, ctx: MethodContext, lookup_cls: type, field: Union["Field[Any, Any]", ForeignObjectRel] | None = None | ||
| self, ctx: MethodContext, lookup_cls: type, field: Field[Any, Any] | ForeignObjectRel | None = None | ||
| ) -> MypyType | None: | ||
| """Resolve the expected type for a lookup class (used both for regular fields and annotated fields) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from mypy.errorcodes import ErrorCode | ||
|
|
||
| MANAGER_MISSING = ErrorCode("django-manager-missing", "Couldn't resolve manager for model", "Django") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
|
|
||
| class UnregisteredModelError(Exception): | ||
| """The requested model is not registered""" |
Uh oh!
There was an error while loading. Please reload this page.