1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
- case: test_filter_on_abstract_user_pk
main: |
from typing_extensions import reveal_type
from django.contrib.auth.models import AbstractUser
AbstractUser.objects.get(pk=1)
AbstractUser.objects.get(pk__in=[1])
au: AbstractUser
reveal_type(au.pk) # N: Revealed type is "Any"
installed_apps:
- django.contrib.auth
- django.contrib.contenttypes
- case: test_filter_on_abstract_user_pk_wrong_name
main: |
from django.contrib.auth.models import AbstractUser
AbstractUser.objects.get(pkey=1) # ER: Cannot resolve keyword 'pkey' into field..*
installed_apps:
- django.contrib.auth
- django.contrib.contenttypes
- case: test_fetch_pk_with_custom_manager_on_abstract_model
main: |
from myapp.models import MyModel
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from typing_extensions import reveal_type
from django.db import models
class BaseManager(models.Manager):
pass
class BaseModel(models.Model):
objects = BaseManager()
class Meta:
abstract = True
def lock(self) -> None:
reveal_type(type(self).objects.values_list("pk")) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.BaseModel, tuple[Any]]"
class MyModel(BaseModel):
field = models.IntegerField()
- case: test_can_instantiate_with_recursive_relation_on_abstract_model
main: |
from myapp.models import Concrete, Recursive
first = Concrete.objects.create(parent=None)
Concrete.objects.create(parent=first)
Recursive.objects.create(parent=None)
Recursive(parent=Recursive(parent=None))
Concrete(parent=Concrete(parent=None))
out: |
main:4: error: "type[Recursive]" has no attribute "objects" [attr-defined]
main:5: error: Cannot instantiate abstract class "Recursive" with abstract attributes "DoesNotExist" and "MultipleObjectsReturned" [abstract]
main:5: error: Unexpected attribute "parent" for model "Recursive" [misc]
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Recursive(models.Model):
parent = models.ForeignKey("self", null=True, on_delete=models.CASCADE)
class Meta:
abstract = True
class Concrete(Recursive):
...
- case: test_abstract_model_type_cannot_be_used_as_runtime_arg
main: |
from myapp.models import Abstract, Concrete, LiteralAbstract
from typing import Generic, TypeVar, overload
Abstract() # E: Cannot instantiate abstract class "Abstract" with abstract attributes "DoesNotExist" and "MultipleObjectsReturned" [abstract]
LiteralAbstract() # E: Cannot instantiate abstract class "LiteralAbstract" with abstract attributes "DoesNotExist" and "MultipleObjectsReturned" [abstract]
def f(klass: type[Abstract]) -> None:
return None
f(Abstract) # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
f(Concrete)
def second_arg(arg: str, klass: type[Abstract]) -> None:
return None
second_arg("abc", Abstract) # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
second_arg(Abstract, Concrete) # E: Argument 1 to "second_arg" has incompatible type "type[Abstract]"; expected "str" [arg-type]
T = TypeVar("T", bound=Abstract)
def g(klass: type[T]) -> None:
return None
g(Abstract) # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
g(Concrete)
@overload
def o(klass: type[T], arg: str) -> None: ...
@overload
def o(klass: type[T], arg: int) -> None: ...
def o(klass: type[T], arg: str | int) -> None:
return None
o(Abstract, "a") # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
o(Abstract, 1) # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
o(Concrete, 1)
class M:
def method(self, klass: type[Abstract]) -> None:
return None
@overload
def overloaded(self, arg: int, klass: type[Abstract]) -> None:
...
@overload
def overloaded(self, arg: str, klass: type[Abstract]) -> None:
...
def overloaded(self, arg: str | int, klass: type[Abstract]) -> None:
return None
M().method(Abstract) # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
M().overloaded(1, Abstract) # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
M().overloaded("1", Abstract) # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
class G(Generic[T]):
def method(self, klass: type[T]) -> None:
return None
G[Abstract]().method(Abstract) # E: Only concrete class can be given where "type[Abstract]" is expected [type-abstract]
# Additional plugin coverage
unknown(Abstract) # E: Name "unknown" is not defined [name-defined]
M().unknown(Abstract) # E: "M" has no attribute "unknown" [attr-defined]
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from typing import Literal, ClassVar
class Abstract(models.Model):
field = models.CharField()
class Meta:
abstract = True
class Concrete(Abstract):
...
class LiteralAbstract(models.Model):
class Meta:
abstract: ClassVar[Literal[True]]
- case: test_use_abstract_model
main: |
from myapp.models import create_animal, create_animal_generic, Cat, Animal, ExplicitConcrete
create_animal(Cat, "Garfield")
create_animal(Animal, "Animal") # E: Only concrete class can be given where "type[Animal]" is expected [type-abstract]
create_animal_generic(Cat, "Grumpy")
create_animal_generic(Animal, "Animal") # E: Only concrete class can be given where "type[Animal]" is expected [type-abstract]
Animal() # E: Cannot instantiate abstract class "Animal" with abstract attributes "DoesNotExist" and "MultipleObjectsReturned" [abstract]
ExplicitConcrete()
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from typing import Protocol, TypeVar
from typing_extensions import reveal_type
from django.db import models
from django_stubs_ext.db.models import TypedModelMeta
class Animal(models.Model):
name = models.CharField(max_length=100)
class Meta(TypedModelMeta):
abstract = True
class Cat(Animal): # Concrete model
pass
class ExplicitConcrete(Animal):
class Meta:
abstract = False
def f() -> None:
x: type[Animal]
x()
return None
def create_animal(klass: type[Animal], name: str) -> Animal:
obj = klass(name=name)
obj.save()
return obj
T = TypeVar("T", bound=Animal)
def create_animal_generic(klass: type[T], name: str) -> T:
reveal_type(klass) # N: Revealed type is "type[T`-1]"
return klass._default_manager.create(name=name)
|