From 3026dc8ef38bdd1053a9811e31dcd068a92498d5 Mon Sep 17 00:00:00 2001 From: SaJH Date: Mon, 13 May 2024 02:59:25 +0900 Subject: [PATCH 1/4] Add typing of django.db.models.fields.related.ForeignObject --- django-stubs/db/models/fields/related.pyi | 25 ++++++++++- scripts/stubtest/allowlist_todo.txt | 52 ----------------------- 2 files changed, 24 insertions(+), 53 deletions(-) diff --git a/django-stubs/db/models/fields/related.pyi b/django-stubs/db/models/fields/related.pyi index 73ca3da7d..757d81ce5 100644 --- a/django-stubs/db/models/fields/related.pyi +++ b/django-stubs/db/models/fields/related.pyi @@ -5,7 +5,14 @@ from uuid import UUID from django.core import validators # due to weird mypy.stubtest error from django.db.models.base import Model from django.db.models.expressions import Combinable, Expression -from django.db.models.fields import NOT_PROVIDED, Field, _AllLimitChoicesTo, _ErrorMessagesMapping, _LimitChoicesTo +from django.db.models.fields import ( + NOT_PROVIDED, + Empty, + Field, + _AllLimitChoicesTo, + _ErrorMessagesMapping, + _LimitChoicesTo, +) from django.db.models.fields.mixins import FieldCacheMixin from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor as ForwardManyToOneDescriptor from django.db.models.fields.related_descriptors import ForwardOneToOneDescriptor as ForwardOneToOneDescriptor @@ -87,6 +94,9 @@ class RelatedField(FieldCacheMixin, Field[_ST, _GT]): class ForeignObject(RelatedField[_ST, _GT]): remote_field: ForeignObjectRel + requires_unique_target: bool + related_accessor_class: type[ReverseManyToOneDescriptor] + forward_related_accessor_class: type[ForwardManyToOneDescriptor] rel_class: type[ForeignObjectRel] from_fields: Sequence[str] to_fields: Sequence[str | None] # None occurs in ForeignKey, where to_field defaults to None @@ -124,6 +134,7 @@ class ForeignObject(RelatedField[_ST, _GT]): error_messages: _ErrorMessagesMapping | None = ..., db_comment: str | None = ..., ) -> None: ... + def __copy__(self) -> Empty: ... # class access @overload def __get__(self, instance: None, owner: Any) -> ForwardManyToOneDescriptor[Self]: ... @@ -142,6 +153,18 @@ class ForeignObject(RelatedField[_ST, _GT]): def local_related_fields(self) -> tuple[Field, ...]: ... @cached_property def foreign_related_fields(self) -> tuple[Field, ...]: ... + def get_local_related_value(self, instance: Model) -> tuple[list[Any], ...]: ... + def get_foreign_related_value(self, instance: Model) -> tuple[list[Any], ...]: ... + @staticmethod + def get_instance_value_for_fields(instance: Model, fields: Sequence[Field]) -> tuple[list[Any], ...]: ... + def get_joining_columns(self, reverse_join: bool = False) -> tuple[tuple[str, str], ...]: ... + def get_reverse_joining_columns(self) -> tuple[tuple[str, str], ...]: ... + def get_extra_descriptor_filter(self, instance: Model) -> dict[str, Any]: ... + def get_path_info(self, filtered_relation: FilteredRelation | None = ...) -> list[PathInfo]: ... + def get_reverse_path_info(self, filtered_relation: FilteredRelation | None = ...) -> list[PathInfo]: ... + @classmethod + def get_class_lookups(cls) -> dict[str, Any]: ... + def contribute_to_related_class(self, cls: type[Model], related: RelatedField) -> None: ... class ForeignKey(ForeignObject[_ST, _GT]): _pyi_private_set_type: Any | Combinable diff --git a/scripts/stubtest/allowlist_todo.txt b/scripts/stubtest/allowlist_todo.txt index 111c84dcd..cc5e9241e 100644 --- a/scripts/stubtest/allowlist_todo.txt +++ b/scripts/stubtest/allowlist_todo.txt @@ -290,28 +290,13 @@ django.contrib.gis.db.models.FileField.formfield django.contrib.gis.db.models.FilePathField.formfield django.contrib.gis.db.models.FloatField.formfield django.contrib.gis.db.models.ForeignKey.__class_getitem__ -django.contrib.gis.db.models.ForeignKey.contribute_to_related_class django.contrib.gis.db.models.ForeignKey.convert_empty_strings django.contrib.gis.db.models.ForeignKey.descriptor_class django.contrib.gis.db.models.ForeignKey.formfield django.contrib.gis.db.models.ForeignKey.get_db_converters -django.contrib.gis.db.models.ForeignObject.__copy__ django.contrib.gis.db.models.ForeignObject.__get__ -django.contrib.gis.db.models.ForeignObject.contribute_to_related_class -django.contrib.gis.db.models.ForeignObject.forward_related_accessor_class -django.contrib.gis.db.models.ForeignObject.get_class_lookups -django.contrib.gis.db.models.ForeignObject.get_extra_descriptor_filter django.contrib.gis.db.models.ForeignObject.get_extra_restriction -django.contrib.gis.db.models.ForeignObject.get_foreign_related_value -django.contrib.gis.db.models.ForeignObject.get_instance_value_for_fields -django.contrib.gis.db.models.ForeignObject.get_joining_columns -django.contrib.gis.db.models.ForeignObject.get_local_related_value -django.contrib.gis.db.models.ForeignObject.get_path_info -django.contrib.gis.db.models.ForeignObject.get_reverse_joining_columns -django.contrib.gis.db.models.ForeignObject.get_reverse_path_info django.contrib.gis.db.models.ForeignObject.path_infos -django.contrib.gis.db.models.ForeignObject.related_accessor_class -django.contrib.gis.db.models.ForeignObject.requires_unique_target django.contrib.gis.db.models.ForeignObject.reverse_path_infos django.contrib.gis.db.models.ForeignObjectRel.__init__ django.contrib.gis.db.models.ForeignObjectRel.empty_strings_allowed @@ -357,8 +342,6 @@ django.contrib.gis.db.models.Model.add_to_class django.contrib.gis.db.models.ObjectDoesNotExist django.contrib.gis.db.models.OneToOneField.__get__ django.contrib.gis.db.models.OneToOneField.formfield -django.contrib.gis.db.models.OneToOneField.forward_related_accessor_class -django.contrib.gis.db.models.OneToOneField.related_accessor_class django.contrib.gis.db.models.OneToOneRel.__init__ django.contrib.gis.db.models.OrderBy.as_oracle django.contrib.gis.db.models.OrderBy.as_sql @@ -727,28 +710,13 @@ django.db.models.FileField.formfield django.db.models.FilePathField.formfield django.db.models.FloatField.formfield django.db.models.ForeignKey.__class_getitem__ -django.db.models.ForeignKey.contribute_to_related_class django.db.models.ForeignKey.convert_empty_strings django.db.models.ForeignKey.descriptor_class django.db.models.ForeignKey.formfield django.db.models.ForeignKey.get_db_converters -django.db.models.ForeignObject.__copy__ django.db.models.ForeignObject.__get__ -django.db.models.ForeignObject.contribute_to_related_class -django.db.models.ForeignObject.forward_related_accessor_class -django.db.models.ForeignObject.get_class_lookups -django.db.models.ForeignObject.get_extra_descriptor_filter django.db.models.ForeignObject.get_extra_restriction -django.db.models.ForeignObject.get_foreign_related_value -django.db.models.ForeignObject.get_instance_value_for_fields -django.db.models.ForeignObject.get_joining_columns -django.db.models.ForeignObject.get_local_related_value -django.db.models.ForeignObject.get_path_info -django.db.models.ForeignObject.get_reverse_joining_columns -django.db.models.ForeignObject.get_reverse_path_info django.db.models.ForeignObject.path_infos -django.db.models.ForeignObject.related_accessor_class -django.db.models.ForeignObject.requires_unique_target django.db.models.ForeignObject.reverse_path_infos django.db.models.ForeignObjectRel.__init__ django.db.models.ForeignObjectRel.empty_strings_allowed @@ -792,8 +760,6 @@ django.db.models.Model.add_to_class django.db.models.ObjectDoesNotExist django.db.models.OneToOneField.__get__ django.db.models.OneToOneField.formfield -django.db.models.OneToOneField.forward_related_accessor_class -django.db.models.OneToOneField.related_accessor_class django.db.models.OneToOneRel.__init__ django.db.models.OrderBy.as_oracle django.db.models.OrderBy.as_sql @@ -969,28 +935,12 @@ django.db.models.fields.json.KeyTransform.as_sqlite django.db.models.fields.json.KeyTransformIsNull.as_sqlite django.db.models.fields.json.KeyTransformNumericLookupMixin.process_rhs django.db.models.fields.related.ForeignKey.__class_getitem__ -django.db.models.fields.related.ForeignKey.contribute_to_related_class django.db.models.fields.related.ForeignKey.convert_empty_strings django.db.models.fields.related.ForeignKey.descriptor_class django.db.models.fields.related.ForeignKey.formfield django.db.models.fields.related.ForeignKey.get_db_converters -django.db.models.fields.related.ForeignObject.__copy__ django.db.models.fields.related.ForeignObject.__get__ -django.db.models.fields.related.ForeignObject.contribute_to_related_class -django.db.models.fields.related.ForeignObject.forward_related_accessor_class -django.db.models.fields.related.ForeignObject.get_class_lookups -django.db.models.fields.related.ForeignObject.get_extra_descriptor_filter django.db.models.fields.related.ForeignObject.get_extra_restriction -django.db.models.fields.related.ForeignObject.get_foreign_related_value -django.db.models.fields.related.ForeignObject.get_instance_value_for_fields -django.db.models.fields.related.ForeignObject.get_joining_columns -django.db.models.fields.related.ForeignObject.get_local_related_value -django.db.models.fields.related.ForeignObject.get_path_info -django.db.models.fields.related.ForeignObject.get_reverse_joining_columns -django.db.models.fields.related.ForeignObject.get_reverse_path_info -django.db.models.fields.related.ForeignObject.path_infos -django.db.models.fields.related.ForeignObject.related_accessor_class -django.db.models.fields.related.ForeignObject.requires_unique_target django.db.models.fields.related.ForeignObject.reverse_path_infos django.db.models.fields.related.ForeignObjectRel.__init__ django.db.models.fields.related.ForeignObjectRel.empty_strings_allowed @@ -1015,8 +965,6 @@ django.db.models.fields.related.ManyToOneRel.__init__ django.db.models.fields.related.ManyToOneRel.identity django.db.models.fields.related.OneToOneField.__get__ django.db.models.fields.related.OneToOneField.formfield -django.db.models.fields.related.OneToOneField.forward_related_accessor_class -django.db.models.fields.related.OneToOneField.related_accessor_class django.db.models.fields.related.OneToOneRel.__init__ django.db.models.fields.related.RelatedField.formfield django.db.models.fields.related.lazy_related_operation From dbd8b3dad96ebd0e6e7b68e70a2927abd37bada8 Mon Sep 17 00:00:00 2001 From: Jae Hyuck Sa Date: Mon, 13 May 2024 04:14:05 +0900 Subject: [PATCH 2/4] Update allowlist_todo.txt --- scripts/stubtest/allowlist_todo.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/stubtest/allowlist_todo.txt b/scripts/stubtest/allowlist_todo.txt index cc5e9241e..9394a70fa 100644 --- a/scripts/stubtest/allowlist_todo.txt +++ b/scripts/stubtest/allowlist_todo.txt @@ -940,6 +940,7 @@ django.db.models.fields.related.ForeignKey.descriptor_class django.db.models.fields.related.ForeignKey.formfield django.db.models.fields.related.ForeignKey.get_db_converters django.db.models.fields.related.ForeignObject.__get__ +django.db.models.fields.related.ForeignObject.path_infos django.db.models.fields.related.ForeignObject.get_extra_restriction django.db.models.fields.related.ForeignObject.reverse_path_infos django.db.models.fields.related.ForeignObjectRel.__init__ From c866156b50492d00bd3b66baa87cba91e955c996 Mon Sep 17 00:00:00 2001 From: SaJH Date: Thu, 16 May 2024 15:35:35 +0900 Subject: [PATCH 3/4] Updated parts that required ClassVar --- django-stubs/contrib/contenttypes/fields.pyi | 4 +-- django-stubs/db/models/fields/__init__.pyi | 8 ++--- django-stubs/db/models/fields/related.pyi | 34 ++++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/django-stubs/contrib/contenttypes/fields.pyi b/django-stubs/contrib/contenttypes/fields.pyi index 0e30ab039..f8a28350a 100644 --- a/django-stubs/contrib/contenttypes/fields.pyi +++ b/django-stubs/contrib/contenttypes/fields.pyi @@ -1,5 +1,5 @@ from collections.abc import Callable -from typing import Any +from typing import Any, ClassVar from django.contrib.contenttypes.models import ContentType from django.core.checks.messages import CheckMessage @@ -67,7 +67,7 @@ class GenericRel(ForeignObjectRel): ) -> None: ... class GenericRelation(ForeignObject): - rel_class: Any + rel_class: ClassVar[Any] mti_inherited: bool object_id_field_name: str content_type_field_name: str diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index effe1e133..dbdea33b0 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -120,10 +120,10 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]): remote_field: ForeignObjectRel | None is_relation: bool related_model: type[Model] | Literal["self"] | None - one_to_many: bool | None - one_to_one: bool | None - many_to_many: bool | None - many_to_one: bool | None + one_to_many: ClassVar[bool | None] + one_to_one: ClassVar[bool | None] + many_to_many: ClassVar[bool | None] + many_to_one: ClassVar[bool | None] max_length: int | None model: type[Model] name: str diff --git a/django-stubs/db/models/fields/related.pyi b/django-stubs/db/models/fields/related.pyi index 50ab4a6cf..64e1a691f 100644 --- a/django-stubs/db/models/fields/related.pyi +++ b/django-stubs/db/models/fields/related.pyi @@ -1,5 +1,5 @@ from collections.abc import Callable, Iterable, Sequence -from typing import Any, Generic, Literal, TypeVar, overload +from typing import Any, ClassVar, Generic, Literal, TypeVar, overload from uuid import UUID from django.core import validators # due to weird mypy.stubtest error @@ -39,14 +39,14 @@ _ST = TypeVar("_ST") _GT = TypeVar("_GT") class RelatedField(FieldCacheMixin, Field[_ST, _GT]): - one_to_many: bool - one_to_one: bool - many_to_many: bool - many_to_one: bool + one_to_many: ClassVar[bool] + one_to_one: ClassVar[bool] + many_to_many: ClassVar[bool] + many_to_one: ClassVar[bool] opts: Any remote_field: ForeignObjectRel - rel_class: type[ForeignObjectRel] + rel_class: ClassVar[type[ForeignObjectRel]] swappable: bool def __init__( self, @@ -94,10 +94,10 @@ class RelatedField(FieldCacheMixin, Field[_ST, _GT]): class ForeignObject(RelatedField[_ST, _GT]): remote_field: ForeignObjectRel - requires_unique_target: bool - related_accessor_class: type[ReverseManyToOneDescriptor] - forward_related_accessor_class: type[ForwardManyToOneDescriptor] - rel_class: type[ForeignObjectRel] + requires_unique_target: ClassVar[bool] + related_accessor_class: ClassVar[type[ReverseManyToOneDescriptor]] + forward_related_accessor_class: ClassVar[type[ForwardManyToOneDescriptor]] + rel_class: ClassVar[type[ForeignObjectRel]] from_fields: Sequence[str] to_fields: Sequence[str | None] # None occurs in ForeignKey, where to_field defaults to None swappable: bool @@ -173,7 +173,7 @@ class ForeignKey(ForeignObject[_ST, _GT]): _pyi_private_get_type: Any remote_field: ManyToOneRel - rel_class: type[ManyToOneRel] + rel_class: ClassVar[type[ManyToOneRel]] def __init__( self, to: type[Model] | str, @@ -215,7 +215,7 @@ class OneToOneField(ForeignKey[_ST, _GT]): _pyi_private_get_type: Any remote_field: OneToOneRel - rel_class: type[OneToOneRel] + rel_class: ClassVar[type[OneToOneRel]] def __init__( self, to: type[Model] | str, @@ -269,13 +269,13 @@ class ManyToManyField(RelatedField[Any, Any], Generic[_To, _Through]): has_null_arg: bool swappable: bool - many_to_many: Literal[True] - many_to_one: Literal[False] - one_to_many: Literal[False] - one_to_one: Literal[False] + many_to_many: ClassVar[Literal[True]] + many_to_one: ClassVar[Literal[False]] + one_to_many: ClassVar[Literal[False]] + one_to_one: ClassVar[Literal[False]] remote_field: ManyToManyRel - rel_class: type[ManyToManyRel] + rel_class: ClassVar[type[ManyToManyRel]] def __init__( self, to: type[_To] | str, From 0a91481be7c43f9192332da992802f40a7637ecb Mon Sep 17 00:00:00 2001 From: SaJH Date: Thu, 16 May 2024 15:38:47 +0900 Subject: [PATCH 4/4] Update the __copy__ method --- django-stubs/db/models/fields/related.pyi | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/django-stubs/db/models/fields/related.pyi b/django-stubs/db/models/fields/related.pyi index 64e1a691f..d6358fa63 100644 --- a/django-stubs/db/models/fields/related.pyi +++ b/django-stubs/db/models/fields/related.pyi @@ -5,14 +5,7 @@ from uuid import UUID from django.core import validators # due to weird mypy.stubtest error from django.db.models.base import Model from django.db.models.expressions import Combinable, Expression -from django.db.models.fields import ( - NOT_PROVIDED, - Empty, - Field, - _AllLimitChoicesTo, - _ErrorMessagesMapping, - _LimitChoicesTo, -) +from django.db.models.fields import NOT_PROVIDED, Field, _AllLimitChoicesTo, _ErrorMessagesMapping, _LimitChoicesTo from django.db.models.fields.mixins import FieldCacheMixin from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor as ForwardManyToOneDescriptor from django.db.models.fields.related_descriptors import ForwardOneToOneDescriptor as ForwardOneToOneDescriptor @@ -134,7 +127,7 @@ class ForeignObject(RelatedField[_ST, _GT]): error_messages: _ErrorMessagesMapping | None = ..., db_comment: str | None = ..., ) -> None: ... - def __copy__(self) -> Empty: ... + def __copy__(self) -> Self: ... # class access @overload def __get__(self, instance: None, owner: Any) -> ForwardManyToOneDescriptor[Self]: ...