Skip to content

Commit

Permalink
Fix typing of related manager methods (#2439)
Browse files Browse the repository at this point in the history
Looking at the [related manager documentation][0] it isn't very clear
that the `bulk` argument only applies to `RelatedManager` and the
`through_defaults` argument only applies to `ManyRelatedManager`.

Based on the [related descriptors source][1], the following changes have
been made in this commit:

- The `bulk` argument has been added to `.clear()` and `.aclear()` for
  `RelatedManager`
- The `bulk` argument has been removed from all methods of
  `ManyRelatedManager`
- Additional methods using `through_defaults` have been added to
  `ManyRelatedManager`.
- Updated typing of `through_defaults` to `Mapping[str, Any] | None`

[0]: https://docs.djangoproject.com/en/stable/ref/models/relations/
[1]: https://github.com/django/django/blob/042b381e2e37c0c37b8a8f6cc9947f1a2ebfa0dd/django/db/models/fields/related_descriptors.py
  • Loading branch information
ngnpope authored Nov 9, 2024
1 parent 0b6e8b3 commit fdb8aca
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 16 deletions.
86 changes: 71 additions & 15 deletions django-stubs/db/models/fields/related_descriptors.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from collections.abc import Callable, Iterable
from collections.abc import Callable, Iterable, Mapping
from typing import Any, Generic, NoReturn, TypeVar, overload, type_check_only

from django.core.exceptions import ObjectDoesNotExist
Expand Down Expand Up @@ -102,10 +102,22 @@ class RelatedManager(Manager[_To], Generic[_To]):
async def aadd(self, *objs: _To | int, bulk: bool = ...) -> None: ...
def remove(self, *objs: _To | int, bulk: bool = ...) -> None: ...
async def aremove(self, *objs: _To | int, bulk: bool = ...) -> None: ...
def set(self, objs: QuerySet[_To] | Iterable[_To | int], *, bulk: bool = ..., clear: bool = ...) -> None: ...
async def aset(self, objs: QuerySet[_To] | Iterable[_To | int], *, bulk: bool = ..., clear: bool = ...) -> None: ...
def clear(self) -> None: ...
async def aclear(self) -> None: ...
def clear(self, *, clear: bool = ...) -> None: ...
async def aclear(self, *, clear: bool = ...) -> None: ...
def set(
self,
objs: QuerySet[_To] | Iterable[_To | int],
*,
bulk: bool = ...,
clear: bool = ...,
) -> None: ...
async def aset(
self,
objs: QuerySet[_To] | Iterable[_To | int],
*,
bulk: bool = ...,
clear: bool = ...,
) -> None: ...
def __call__(self, *, manager: str) -> RelatedManager[_To]: ...

def create_reverse_many_to_one_manager(
Expand Down Expand Up @@ -142,28 +154,72 @@ class ManyToManyDescriptor(ReverseManyToOneDescriptor, Generic[_To, _Through]):
class ManyRelatedManager(Manager[_To], Generic[_To, _Through]):
related_val: tuple[int, ...]
through: type[_Through]
def add(self, *objs: _To | int, bulk: bool = ..., through_defaults: dict[str, Any] | None = ...) -> None: ...
async def aadd(self, *objs: _To | int, bulk: bool = ..., through_defaults: dict[str, Any] | None = ...) -> None: ...
def remove(self, *objs: _To | int, bulk: bool = ...) -> None: ...
async def aremove(self, *objs: _To | int, bulk: bool = ...) -> None: ...
def add(
self,
*objs: _To | int,
through_defaults: Mapping[str, Any] | None = ...,
) -> None: ...
async def aadd(
self,
*objs: _To | int,
through_defaults: Mapping[str, Any] | None = ...,
) -> None: ...
def remove(self, *objs: _To | int) -> None: ...
async def aremove(self, *objs: _To | int) -> None: ...
def clear(self) -> None: ...
async def aclear(self) -> None: ...
def set(
self,
objs: QuerySet[_To] | Iterable[_To | int],
*,
bulk: bool = ...,
clear: bool = ...,
through_defaults: dict[str, Any] | None = ...,
through_defaults: Mapping[str, Any] | None = ...,
) -> None: ...
async def aset(
self,
objs: QuerySet[_To] | Iterable[_To | int],
*,
bulk: bool = ...,
clear: bool = ...,
through_defaults: dict[str, Any] | None = ...,
through_defaults: Mapping[str, Any] | None = ...,
) -> None: ...
def clear(self) -> None: ...
async def aclear(self) -> None: ...
def create(
self,
*,
through_defaults: Mapping[str, Any] | None = ...,
**kwargs: Any,
) -> _To: ...
async def acreate(
self,
*,
through_defaults: Mapping[str, Any] | None = ...,
**kwargs: Any,
) -> _To: ...
def get_or_create(
self,
defaults: Mapping[str, Any] | None = ...,
through_defaults: Mapping[str, Any] | None = ...,
**kwargs: Any,
) -> tuple[_To, bool]: ...
async def aget_or_create(
self,
defaults: Mapping[str, Any] | None = ...,
through_defaults: Mapping[str, Any] | None = ...,
**kwargs: Any,
) -> tuple[_To, bool]: ...
def update_or_create(
self,
defaults: Mapping[str, Any] | None = ...,
create_defaults: Mapping[str, Any] | None = ...,
through_defaults: Mapping[str, Any] | None = ...,
**kwargs: Any,
) -> tuple[_To, bool]: ...
async def aupdate_or_create(
self,
defaults: Mapping[str, Any] | None = ...,
create_defaults: Mapping[str, Any] | None = ...,
through_defaults: Mapping[str, Any] | None = ...,
**kwargs: Any,
) -> tuple[_To, bool]: ...
def __call__(self, *, manager: str) -> ManyRelatedManager[_To, _Through]: ...

def create_forward_many_to_many_manager(
Expand Down
2 changes: 1 addition & 1 deletion tests/typecheck/fields/test_related.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,7 @@
main:26: note: Revealed type is "myapp.models.MyModel_auto_through"
main:28: note: Revealed type is "builtins.str"
main:29: note: Revealed type is "builtins.str"
main:30: note: Revealed type is "def (*objs: Union[myapp.models.MyModel, builtins.int], bulk: builtins.bool =, through_defaults: Union[builtins.dict[builtins.str, Any], None] =)"
main:30: note: Revealed type is "def (*objs: Union[myapp.models.MyModel, builtins.int], through_defaults: Union[typing.Mapping[builtins.str, Any], None] =)"
main:32: note: Revealed type is "django.db.models.manager.Manager[myapp.models.MyModel_auto_through]"
main:33: note: Revealed type is "django.db.models.manager.Manager[myapp.models.MyModel_auto_through]"
main:35: note: Revealed type is "myapp.models.Other_ManyRelatedManager[myapp.models.MyModel_auto_through]"
Expand Down

0 comments on commit fdb8aca

Please sign in to comment.