Skip to content

Commit 8035abb

Browse files
committed
Fix row type of FallbackQuerySet
Because this inherits from _QuerySet, not QuerySet, it needs to have two parameters
1 parent 2d3d6ff commit 8035abb

File tree

3 files changed

+30
-9
lines changed

3 files changed

+30
-9
lines changed

mypy_django_plugin/transformers/managers.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,21 @@ def get_funcdef_type(definition: Union[FuncBase, Decorator, None]) -> Optional[P
8787
variables = method_type.variables
8888
ret_type = method_type.ret_type
8989

90+
is_fallback_queryset = queryset_info.metadata.get("django", {}).get("any_fallback_queryset", False)
91+
9092
# For methods on the manager that return a queryset we need to override the
9193
# return type to be the actual queryset class, not the base QuerySet that's
9294
# used by the typing stubs.
9395
if method_name in MANAGER_METHODS_RETURNING_QUERYSET:
94-
ret_type = Instance(queryset_info, manager_instance.args)
96+
if not is_fallback_queryset:
97+
ret_type = Instance(queryset_info, manager_instance.args)
98+
else:
99+
# The fallback queryset inherits _QuerySet, which has two generics
100+
# instead of the one exposed on QuerySet. That means that we need
101+
# to add the model twice. In real code it's not possible to inherit
102+
# from _QuerySet, as it doesn't exist at runtime, so this fix is
103+
# only needed for pluign-generated querysets.
104+
ret_type = Instance(queryset_info, [manager_instance.args[0], manager_instance.args[0]])
95105
variables = []
96106

97107
# Drop any 'self' argument as our manager is already initialized

mypy_django_plugin/transformers/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ def get_or_create_queryset_with_any_fallback(self) -> TypeInfo:
160160
}
161161
queryset_info.fallback_to_any = True
162162

163-
queryset_info.type_vars = base_queryset_info.type_vars
164-
queryset_info.defn.type_vars = base_queryset_info.defn.type_vars
163+
queryset_info.type_vars = base_queryset_info.type_vars.copy()
164+
queryset_info.defn.type_vars = base_queryset_info.defn.type_vars.copy()
165165
queryset_info.metaclass_type = queryset_info.calculate_metaclass_type()
166166

167167
return queryset_info

tests/typecheck/managers/test_managers.yml

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -508,12 +508,18 @@
508508
reveal_type(Booking.objects.custom)
509509
reveal_type(Booking.objects.all().filter)
510510
reveal_type(Booking.objects.all().custom)
511+
reveal_type(Booking.objects.first())
512+
reveal_type(Booking.objects.get())
513+
reveal_type([booking for booking in Booking.objects.all()])
514+
reveal_type([booking for booking in Booking.objects.all().filter()])
515+
511516
512517
# Check QuerySet methods on UnknownRelatedManager
513518
reveal_type(user.booking_set.all)
514519
reveal_type(user.booking_set.custom)
515520
reveal_type(user.booking_set.all().filter)
516521
reveal_type(user.booking_set.all().custom)
522+
reveal_type(user.booking_set.all().first())
517523
out: |
518524
myapp/models:13: error: Couldn't resolve related manager for relation 'booking' (from myapp.models.Booking.myapp.Booking.renter).
519525
myapp/models:13: error: Couldn't resolve related manager for relation 'bookingowner_set' (from myapp.models.Booking.myapp.Booking.owner).
@@ -533,11 +539,16 @@
533539
myapp/models:47: note: Revealed type is "django.db.models.manager.BaseManager[myapp.models.InvisibleUnresolvable]"
534540
myapp/models:49: note: Revealed type is "myapp.models.UnknownRelatedManager[myapp.models.Booking]"
535541
myapp/models:50: note: Revealed type is "myapp.models.UnknownRelatedManager[myapp.models.Booking]"
536-
myapp/models:53: note: Revealed type is "def () -> myapp.models.UnknownQuerySet[myapp.models.Booking]"
542+
myapp/models:53: note: Revealed type is "def () -> myapp.models.UnknownQuerySet[myapp.models.Booking, myapp.models.Booking]"
537543
myapp/models:54: note: Revealed type is "Any"
538-
myapp/models:55: note: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.UnknownQuerySet[myapp.models.Booking]"
544+
myapp/models:55: note: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.UnknownQuerySet[myapp.models.Booking, myapp.models.Booking]"
539545
myapp/models:56: note: Revealed type is "Any"
540-
myapp/models:59: note: Revealed type is "def () -> myapp.models.UnknownQuerySet[myapp.models.Booking]"
541-
myapp/models:60: note: Revealed type is "Any"
542-
myapp/models:61: note: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.UnknownQuerySet[myapp.models.Booking]"
543-
myapp/models:62: note: Revealed type is "Any"
546+
myapp/models:57: note: Revealed type is "Union[myapp.models.Booking, None]"
547+
myapp/models:58: note: Revealed type is "myapp.models.Booking"
548+
myapp/models:59: note: Revealed type is "builtins.list[myapp.models.Booking]"
549+
myapp/models:60: note: Revealed type is "builtins.list[myapp.models.Booking]"
550+
myapp/models:64: note: Revealed type is "def () -> myapp.models.UnknownQuerySet[myapp.models.Booking, myapp.models.Booking]"
551+
myapp/models:65: note: Revealed type is "Any"
552+
myapp/models:66: note: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.UnknownQuerySet[myapp.models.Booking, myapp.models.Booking]"
553+
myapp/models:67: note: Revealed type is "Any"
554+
myapp/models:68: note: Revealed type is "Union[myapp.models.Booking, None]"

0 commit comments

Comments
 (0)