Files
django-stubs/test-data/typecheck/managers.test
Seth Yastrov 86c63d790b Fix type errors on other models' managers when using objects = models.Manager() in Model. (#34)
* Fix bug where models with a class variable using a manager defined would interfere with other managers.

- Fill in the type argument for that particular instance of the manager, rather than modifying the bases of the Manager type.
- Instantiate a new Instance from determine_proper_manager_type so The code doesn't crash under mypy-mypyc.

* Use helpers.reparametrize_instance per review comment.

* Updated ignored errors in Django test for get_objects_or_404.

- For some reason, `Manager[nothing]` is now removed from expected types.
  However, I think this makes sense anyway, as Manager is a subclass of QuerySet.
2019-03-08 12:30:38 +03:00

201 lines
7.4 KiB
Plaintext

[CASE test_every_model_has_objects_queryset_available]
from django.db import models
class User(models.Model):
pass
reveal_type(User.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.User]'
reveal_type(User.objects.get()) # E: Revealed type is 'main.User*'
[CASE every_model_has_its_own_objects_queryset]
from django.db import models
class Parent(models.Model):
pass
class Child(Parent):
pass
reveal_type(Parent.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.Parent]'
reveal_type(Child.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.Child]'
[out]
[CASE if_manager_is_defined_on_model_do_not_add_objects]
from django.db import models
class MyModel(models.Model):
authors = models.Manager[MyModel]()
reveal_type(MyModel.authors) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel]'
reveal_type(MyModel.objects) # E: Revealed type is 'Any'
[out]
[CASE test_model_objects_attribute_present_in_case_of_model_cls_passed_as_generic_parameter]
from typing import TypeVar, Generic, Type
from django.db import models
_T = TypeVar('_T', bound=models.Model)
class Base(Generic[_T]):
def __init__(self, model_cls: Type[_T]):
self.model_cls = model_cls
reveal_type(self.model_cls._default_manager) # E: Revealed type is 'django.db.models.manager.Manager[django.db.models.base.Model]'
class MyModel(models.Model):
pass
base_instance = Base(MyModel)
reveal_type(base_instance.model_cls._default_manager) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel]'
class Child(Base[MyModel]):
def method(self) -> None:
reveal_type(self.model_cls._default_manager) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel]'
[CASE if_custom_manager_defined_it_is_set_to_default_manager]
from typing import TypeVar
from django.db import models
_T = TypeVar('_T', bound=models.Model)
class CustomManager(models.Manager[_T]):
pass
class MyModel(models.Model):
manager = CustomManager[MyModel]()
reveal_type(MyModel._default_manager) # E: Revealed type is 'main.CustomManager[main.MyModel]'
[CASE if_default_manager_name_is_passed_set_default_manager_to_it]
from typing import TypeVar
from django.db import models
_T = TypeVar('_T', bound=models.Model)
class Manager1(models.Manager[_T]):
pass
class Manager2(models.Manager[_T]):
pass
class MyModel(models.Model):
class Meta:
default_manager_name = 'm2'
m1: Manager1[MyModel]
m2: Manager2[MyModel]
reveal_type(MyModel._default_manager) # E: Revealed type is 'main.Manager2[main.MyModel]'
[CASE test_leave_as_is_if_objects_is_set_and_fill_typevars_with_outer_class]
from django.db import models
class UserManager(models.Manager[MyUser]):
def get_or_404(self) -> MyUser:
pass
class MyUser(models.Model):
objects = UserManager()
reveal_type(MyUser.objects) # E: Revealed type is 'main.UserManager[main.MyUser]'
reveal_type(MyUser.objects.get()) # E: Revealed type is 'main.MyUser*'
reveal_type(MyUser.objects.get_or_404()) # E: Revealed type is 'main.MyUser'
[CASE model_imported_from_different_file]
from django.db import models
from models.main import Inventory
class Band(models.Model):
pass
reveal_type(Inventory.objects) # E: Revealed type is 'django.db.models.manager.Manager[models.main.Inventory]'
reveal_type(Band.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.Band]'
[file models/__init__.py]
[file models/main.py]
from django.db import models
class Inventory(models.Model):
pass
[CASE managers_that_defined_on_other_models_do_not_influence]
from django.db import models
class AbstractPerson(models.Model):
abstract_persons = models.Manager[AbstractPerson]()
class PublishedBookManager(models.Manager[Book]):
pass
class AnnotatedBookManager(models.Manager[Book]):
pass
class Book(models.Model):
title = models.CharField(max_length=50)
published_objects = PublishedBookManager()
annotated_objects = AnnotatedBookManager()
reveal_type(AbstractPerson.abstract_persons) # E: Revealed type is 'django.db.models.manager.Manager[main.AbstractPerson]'
reveal_type(Book.published_objects) # E: Revealed type is 'main.PublishedBookManager[main.Book]'
Book.published_objects.create(title='hello')
reveal_type(Book.annotated_objects) # E: Revealed type is 'main.AnnotatedBookManager[main.Book]'
Book.annotated_objects.create(title='hello')
[out]
[CASE managers_inherited_from_abstract_classes_multiple_inheritance]
from django.db import models
class CustomManager1(models.Manager[AbstractBase1]):
pass
class AbstractBase1(models.Model):
class Meta:
abstract = True
name = models.CharField(max_length=50)
manager1 = CustomManager1()
class CustomManager2(models.Manager[AbstractBase2]):
pass
class AbstractBase2(models.Model):
class Meta:
abstract = True
value = models.CharField(max_length=50)
restricted = CustomManager2()
class Child(AbstractBase1, AbstractBase2):
pass
[out]
[CASE managers_from_unrelated_models_dont_interfere]
from django.db import models
# Normal scenario where one model has a manager with an annotation of the same type as the model
class UnrelatedModel(models.Model):
objects = models.Manager[UnrelatedModel]()
class MyModel(models.Model):
pass
reveal_type(UnrelatedModel.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.UnrelatedModel]'
reveal_type(UnrelatedModel.objects.first()) # E: Revealed type is 'Union[main.UnrelatedModel*, None]'
reveal_type(MyModel.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel]'
reveal_type(MyModel.objects.first()) # E: Revealed type is 'Union[main.MyModel*, None]'
# Possible to specify objects without explicit annotation of models.Manager()
class UnrelatedModel2(models.Model):
objects = models.Manager()
class MyModel2(models.Model):
pass
reveal_type(UnrelatedModel2.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.UnrelatedModel2]'
reveal_type(UnrelatedModel2.objects.first()) # E: Revealed type is 'Union[main.UnrelatedModel2*, None]'
reveal_type(MyModel2.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel2]'
reveal_type(MyModel2.objects.first()) # E: Revealed type is 'Union[main.MyModel2*, None]'
# Inheritance works
class ParentOfMyModel3(models.Model):
objects = models.Manager()
class MyModel3(ParentOfMyModel3):
pass
reveal_type(ParentOfMyModel3.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.ParentOfMyModel3]'
reveal_type(ParentOfMyModel3.objects.first()) # E: Revealed type is 'Union[main.ParentOfMyModel3*, None]'
reveal_type(MyModel3.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel3]'
reveal_type(MyModel3.objects.first()) # E: Revealed type is 'Union[main.MyModel3*, None]'
# Inheritance works with explicit objects in child
class ParentOfMyModel4(models.Model):
objects = models.Manager()
class MyModel4(ParentOfMyModel4):
objects = models.Manager[MyModel4]()
reveal_type(ParentOfMyModel4.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.ParentOfMyModel4]'
reveal_type(ParentOfMyModel4.objects.first()) # E: Revealed type is 'Union[main.ParentOfMyModel4*, None]'
reveal_type(MyModel4.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel4]'
reveal_type(MyModel4.objects.first()) # E: Revealed type is 'Union[main.MyModel4*, None]'
[out]