Improve typing for unresolved managers (#1044)

* Improve typing for unresolved managers

This changes the logic when encountering an unresolvable manager class.
Instead of adding it as a `Manager` we create a subclass of `Manager`
that has `fallback_to_any=True` set. Similarly a `QuerySet` class is
created that also has fallbacks to `Any`. This allows calling custom
methods on the manager and querysets without getting type errors.

* Fix manager created and improve a test

* Fix row type of FallbackQuerySet

Because this inherits from _QuerySet, not QuerySet, it needs to have two
parameters
This commit is contained in:
Sigurd Ljødal
2022-07-18 08:13:46 +02:00
committed by GitHub
parent 830d74b493
commit e7a89f73c4
4 changed files with 164 additions and 37 deletions

View File

@@ -678,18 +678,24 @@
def custom(self) -> None:
pass
def TransactionManager():
return BaseManager.from_queryset(TransactionQuerySet)()
class Transaction(models.Model):
objects = BaseManager.from_queryset(TransactionQuerySet)
objects = TransactionManager()
def test(self) -> None:
reveal_type(self.transactionlog_set)
# We use a fallback Any type:
reveal_type(Transaction.objects)
reveal_type(Transaction.objects.custom())
class TransactionLog(models.Model):
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE)
out: |
myapp/models:10: note: Revealed type is "django.db.models.manager.RelatedManager[myapp.models.TransactionLog]"
myapp/models:12: note: Revealed type is "Any"
myapp/models:11: error: Could not resolve manager type for "myapp.models.Transaction.objects"
myapp/models:13: note: Revealed type is "django.db.models.manager.RelatedManager[myapp.models.TransactionLog]"
myapp/models:15: note: Revealed type is "myapp.models.UnknownManager[myapp.models.Transaction]"
myapp/models:16: note: Revealed type is "Any"
- case: resolve_primary_keys_for_foreign_keys_with_abstract_self_model

View File

@@ -502,6 +502,24 @@
reveal_type(user.bookingowner_set)
reveal_type(user.booking_set)
# Check QuerySet methods on UnknownManager
reveal_type(Booking.objects.all)
reveal_type(Booking.objects.custom)
reveal_type(Booking.objects.all().filter)
reveal_type(Booking.objects.all().custom)
reveal_type(Booking.objects.first())
reveal_type(Booking.objects.get())
reveal_type([booking for booking in Booking.objects.all()])
reveal_type([booking for booking in Booking.objects.all().filter()])
# Check QuerySet methods on UnknownRelatedManager
reveal_type(user.booking_set.all)
reveal_type(user.booking_set.custom)
reveal_type(user.booking_set.all().filter)
reveal_type(user.booking_set.all().custom)
reveal_type(user.booking_set.all().first())
out: |
myapp/models:13: error: Couldn't resolve related manager for relation 'booking' (from myapp.models.Booking.myapp.Booking.renter).
myapp/models:13: error: Couldn't resolve related manager for relation 'bookingowner_set' (from myapp.models.Booking.myapp.Booking.owner).
@@ -512,12 +530,25 @@
myapp/models:32: error: Could not resolve manager type for "myapp.models.InvisibleUnresolvable.objects"
myapp/models:36: note: Revealed type is "django.db.models.manager.Manager[myapp.models.User]"
myapp/models:37: note: Revealed type is "django.db.models.manager.Manager[myapp.models.User]"
myapp/models:39: note: Revealed type is "django.db.models.manager.Manager[myapp.models.Booking]"
myapp/models:39: note: Revealed type is "myapp.models.UnknownManager[myapp.models.Booking]"
myapp/models:40: note: Revealed type is "django.db.models.manager.BaseManager[myapp.models.Booking]"
myapp/models:42: note: Revealed type is "django.db.models.manager.Manager[myapp.models.TwoUnresolvable]"
myapp/models:43: note: Revealed type is "django.db.models.manager.Manager[myapp.models.TwoUnresolvable]"
myapp/models:42: note: Revealed type is "myapp.models.UnknownManager[myapp.models.TwoUnresolvable]"
myapp/models:43: note: Revealed type is "myapp.models.UnknownManager[myapp.models.TwoUnresolvable]"
myapp/models:44: note: Revealed type is "django.db.models.manager.BaseManager[myapp.models.TwoUnresolvable]"
myapp/models:46: note: Revealed type is "django.db.models.manager.Manager[myapp.models.InvisibleUnresolvable]"
myapp/models:46: note: Revealed type is "myapp.models.UnknownManager[myapp.models.InvisibleUnresolvable]"
myapp/models:47: note: Revealed type is "django.db.models.manager.BaseManager[myapp.models.InvisibleUnresolvable]"
myapp/models:49: note: Revealed type is "django.db.models.manager.RelatedManager[myapp.models.Booking]"
myapp/models:50: note: Revealed type is "django.db.models.manager.RelatedManager[myapp.models.Booking]"
myapp/models:49: note: Revealed type is "myapp.models.UnknownRelatedManager[myapp.models.Booking]"
myapp/models:50: note: Revealed type is "myapp.models.UnknownRelatedManager[myapp.models.Booking]"
myapp/models:53: note: Revealed type is "def () -> myapp.models.UnknownQuerySet[myapp.models.Booking, myapp.models.Booking]"
myapp/models:54: note: Revealed type is "Any"
myapp/models:55: note: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.UnknownQuerySet[myapp.models.Booking, myapp.models.Booking]"
myapp/models:56: note: Revealed type is "Any"
myapp/models:57: note: Revealed type is "Union[myapp.models.Booking, None]"
myapp/models:58: note: Revealed type is "myapp.models.Booking"
myapp/models:59: note: Revealed type is "builtins.list[myapp.models.Booking]"
myapp/models:60: note: Revealed type is "builtins.list[myapp.models.Booking]"
myapp/models:64: note: Revealed type is "def () -> myapp.models.UnknownQuerySet[myapp.models.Booking, myapp.models.Booking]"
myapp/models:65: note: Revealed type is "Any"
myapp/models:66: note: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.UnknownQuerySet[myapp.models.Booking, myapp.models.Booking]"
myapp/models:67: note: Revealed type is "Any"
myapp/models:68: note: Revealed type is "Union[myapp.models.Booking, None]"