updated package setup (#485)

* updated package setup

* updated to use python 3.9

* fixed test runner

* fixed typecheck tests

* fixed discrepencies

* added override to runner

* updated travis

* updated pre-commit hooks

* updated dep
This commit is contained in:
Na'aman Hirschfeld
2020-10-29 09:59:48 +01:00
committed by GitHub
parent a3624dec36
commit 44151c485d
74 changed files with 1141 additions and 1446 deletions

5
tests/plugins.ini Normal file
View File

@@ -0,0 +1,5 @@
[mypy]
incremental = True
strict_optional = True
plugins =
mypy_django_plugin.main

View File

@@ -0,0 +1,72 @@
import tempfile
import typing
import pytest
from mypy_django_plugin.main import extract_django_settings_module
TEMPLATE = """usage: (config)
...
[mypy.plugins.django_stubs]
django_settings_module: str (required)
...
(django-stubs) mypy: error: 'django_settings_module' is not set: {}
"""
@pytest.mark.parametrize(
"config_file_contents,message_part",
[
pytest.param(
None,
"mypy config file is not specified or found",
id="missing-file",
),
pytest.param(
["[not-really-django-stubs]"],
"no section [mypy.plugins.django-stubs]",
id="missing-section",
),
pytest.param(
["[mypy.plugins.django-stubs]", "\tnot_django_not_settings_module = badbadmodule"],
"the setting is not provided",
id="missing-settings-module",
),
pytest.param(
["[mypy.plugins.django-stubs]"],
"the setting is not provided",
id="no-settings-given",
),
],
)
def test_misconfiguration_handling(capsys, config_file_contents, message_part):
# type: (typing.Any, typing.List[str], str) -> None
"""Invalid configuration raises `SystemExit` with a precise error message."""
with tempfile.NamedTemporaryFile(mode="w+") as config_file:
if not config_file_contents:
config_file.close()
else:
config_file.write("\n".join(config_file_contents).expandtabs(4))
config_file.seek(0)
with pytest.raises(SystemExit, match="2"):
extract_django_settings_module(config_file.name)
error_message = TEMPLATE.format(message_part)
assert error_message == capsys.readouterr().err
def test_correct_configuration() -> None:
"""Django settings module gets extracted given valid configuration."""
config_file_contents = [
"[mypy.plugins.django-stubs]",
"\tsome_other_setting = setting",
"\tdjango_settings_module = my.module",
]
with tempfile.NamedTemporaryFile(mode="w+") as config_file:
config_file.write("\n".join(config_file_contents).expandtabs(4))
config_file.seek(0)
extracted = extract_django_settings_module(config_file.name)
assert extracted == "my.module"

View File

@@ -0,0 +1,148 @@
# "Happy path" test for model admin, trying to cover as many valid
# configurations as possible.
- case: test_full_admin
main: |
from django.contrib import admin
from django.forms import Form, Textarea
from django.db import models
from django.core.paginator import Paginator
from django.contrib.admin.sites import AdminSite
from django.db.models.options import Options
from django.http.request import HttpRequest
from django.db.models.query import QuerySet
def an_action(modeladmin: admin.ModelAdmin, request: HttpRequest, queryset: QuerySet) -> None:
pass
class TestModel(models.Model):
pass
class A(admin.ModelAdmin[TestModel]):
# BaseModelAdmin
autocomplete_fields = ("strs",)
raw_id_fields = ["strs"]
fields = (
"a field",
["a", "list of", "fields"],
)
exclude = ("a", "b")
fieldsets = [
(None, {"fields": ["a", "b"]}),
("group", {"fields": ("c",), "classes": ("a",), "description": "foo"}),
]
form = Form
filter_vertical = ("fields",)
filter_horizontal = ("plenty", "of", "fields")
radio_fields = {
"some_field": admin.VERTICAL,
"another_field": admin.HORIZONTAL,
}
prepopulated_fields = {"slug": ("title",)}
formfield_overrides = {models.TextField: {"widget": Textarea}}
readonly_fields = ("date_modified",)
ordering = ("-pk", "date_modified")
sortable_by = ["pk"]
view_on_site = True
show_full_result_count = False
# ModelAdmin
list_display = ("pk",)
list_display_links = ("str",)
list_filter = ("str", admin.SimpleListFilter, ("str", admin.SimpleListFilter))
list_select_related = True
list_per_page = 1
list_max_show_all = 2
list_editable = ("a", "b")
search_fields = ("c", "d")
date_hirearchy = "f"
save_as = False
save_as_continue = True
save_on_top = False
paginator = Paginator
presserve_filters = False
inlines = (admin.TabularInline, admin.StackedInline)
add_form_template = "template"
change_form_template = "template"
change_list_template = "template"
delete_confirmation_template = "template"
delete_selected_confirmation_template = "template"
object_history_template = "template"
popup_response_template = "template"
actions = (an_action, "a_method_action")
actions_on_top = True
actions_on_bottom = False
actions_selection_counter = True
admin_site = AdminSite()
# test generic ModelAdmin
# https://github.com/typeddjango/django-stubs/pull/504
# this will fail if `model` has a type other than the generic specified in the class declaration
model = TestModel
def a_method_action(self, request, queryset):
pass
# This test is here to make sure we're not running into a mypy issue which is
# worked around using a somewhat complicated _ListOrTuple union type. Once the
# issue is solved upstream this test should pass even with the workaround
# replaced by a simpler Sequence type.
# https://github.com/python/mypy/issues/8921
- case: test_fieldset_workaround_regression
main: |
from django.contrib import admin
class A(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ('name',),
}),
)
- case: errors_on_omitting_fields_from_fieldset_opts
main: |
from django.contrib import admin
class A(admin.ModelAdmin):
fieldsets = [ # type: ignore
(None, {}), # E: Key 'fields' missing for TypedDict "_FieldOpts"
]
- case: errors_on_invalid_radio_fields
main: |
from django.contrib import admin
class A(admin.ModelAdmin):
radio_fields = {"some_field": 0} # E: Dict entry 0 has incompatible type "str": "Literal[0]"; expected "str": "Union[Literal[1], Literal[2]]"
class B(admin.ModelAdmin):
radio_fields = {1: admin.VERTICAL} # E: Dict entry 0 has incompatible type "int": "Literal[2]"; expected "str": "Union[Literal[1], Literal[2]]"
- case: errors_for_invalid_formfield_overrides
main: |
from django.contrib import admin
from django.forms import Textarea
class A(admin.ModelAdmin):
formfield_overrides = {
"not a field": { # E: Dict entry 0 has incompatible type "str": "Dict[str, Any]"; expected "Type[Field[Any, Any]]": "Mapping[str, Any]"
"widget": Textarea
}
}
- case: errors_for_invalid_action_signature
main: |
from django.contrib import admin
from django.http.request import HttpRequest
from django.db.models.query import QuerySet
def an_action(modeladmin: None) -> None:
pass
class A(admin.ModelAdmin):
actions = [an_action] # E: List item 0 has incompatible type "Callable[[None], None]"; expected "Union[Callable[[ModelAdmin[Any], HttpRequest, QuerySet[Any]], None], str]"
- case: errors_for_invalid_model_admin_generic
main: |
from django.contrib.admin import ModelAdmin
from django.db.models import Model
class TestModel(Model):
pass
class A(ModelAdmin[TestModel]):
model = int # E: Incompatible types in assignment (expression has type "Type[int]", base class "ModelAdmin" defined the type as "Type[TestModel]")

View File

@@ -0,0 +1,43 @@
- case: login_required_bare
main: |
from django.contrib.auth.decorators import login_required
@login_required
def view_func(request): ...
reveal_type(view_func) # N: Revealed type is 'def (request: Any) -> Any'
- case: login_required_fancy
main: |
from django.contrib.auth.decorators import login_required
from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponse
@login_required(redirect_field_name='a', login_url='b')
def view_func(request: WSGIRequest, arg: str) -> HttpResponse: ...
reveal_type(view_func) # N: Revealed type is 'def (request: django.core.handlers.wsgi.WSGIRequest, arg: builtins.str) -> django.http.response.HttpResponse'
- case: login_required_weird
main: |
from django.contrib.auth.decorators import login_required
# This is non-conventional usage, but covered in Django tests, so we allow it.
def view_func(request): ...
wrapped_view = login_required(view_func, redirect_field_name='a', login_url='b')
reveal_type(wrapped_view) # N: Revealed type is 'def (request: Any) -> Any'
- case: login_required_incorrect_return
main: |
from django.contrib.auth.decorators import login_required
@login_required() # E: Value of type variable "_VIEW" of function cannot be "Callable[[Any], str]"
def view_func2(request) -> str: ...
- case: user_passes_test
main: |
from django.contrib.auth.decorators import user_passes_test
@user_passes_test(lambda u: u.username.startswith('super'))
def view_func(request): ...
reveal_type(view_func) # N: Revealed type is 'def (request: Any) -> Any'
- case: user_passes_test_bare_is_error
main: |
from django.http.response import HttpResponse
from django.contrib.auth.decorators import user_passes_test
@user_passes_test # E: Argument 1 to "user_passes_test" has incompatible type "Callable[[Any], HttpResponse]"; expected "Callable[[AbstractUser], bool]"
def view_func(request) -> HttpResponse: ...
- case: permission_required
main: |
from django.contrib.auth.decorators import permission_required
@permission_required('polls.can_vote')
def view_func(request): ...

View File

@@ -0,0 +1,26 @@
- case: field_to_many_and_to_one_attrs_bool_or_none_in_field_base_class
main: |
from django.db.models import Field
field: Field
my_bool: bool
my_bool = field.one_to_many
my_bool = field.one_to_one
my_bool = field.many_to_many
my_bool = field.many_to_one
# Narrowing the types should give us bool
assert field.one_to_many is not None
my_bool = field.one_to_many
assert field.one_to_one is not None
my_bool = field.one_to_one
assert field.many_to_many is not None
my_bool = field.many_to_many
assert field.many_to_one is not None
my_bool = field.many_to_one
out: |
main:6: error: Incompatible types in assignment (expression has type "Optional[bool]", variable has type "bool")
main:7: error: Incompatible types in assignment (expression has type "Optional[bool]", variable has type "bool")
main:8: error: Incompatible types in assignment (expression has type "Optional[bool]", variable has type "bool")
main:9: error: Incompatible types in assignment (expression has type "Optional[bool]", variable has type "bool")

View File

@@ -0,0 +1,28 @@
- case: atomic_bare
main: |
from django.db.transaction import atomic
@atomic
def func(x: int) -> list: ...
reveal_type(func) # N: Revealed type is 'def (x: builtins.int) -> builtins.list[Any]'
- case: atomic_args
main: |
from django.db.transaction import atomic
@atomic(using='bla', savepoint=False)
def func(x: int) -> list: ...
reveal_type(func) # N: Revealed type is 'def (x: builtins.int) -> builtins.list[Any]'
- case: non_atomic_requests_bare
main: |
from django.db.transaction import non_atomic_requests
@non_atomic_requests
def view_func(request): ...
reveal_type(view_func) # N: Revealed type is 'def (request: Any) -> Any'
- case: non_atomic_requests_args
main: |
from django.http.request import HttpRequest
from django.http.response import HttpResponse
from django.db.transaction import non_atomic_requests
@non_atomic_requests
def view_func(request: HttpRequest, arg: str) -> HttpResponse: ...
reveal_type(view_func) # N: Revealed type is 'def (request: django.http.request.HttpRequest, arg: builtins.str) -> django.http.response.HttpResponse'

View File

@@ -0,0 +1,153 @@
- case: test_model_fields_classes_present_as_primitives
main: |
from myapp.models import User
user = User(small_int=1, name='user', slug='user', text='user')
reveal_type(user.id) # N: Revealed type is 'builtins.int*'
reveal_type(user.small_int) # N: Revealed type is 'builtins.int*'
reveal_type(user.name) # N: Revealed type is 'builtins.str*'
reveal_type(user.slug) # N: Revealed type is 'builtins.str*'
reveal_type(user.text) # N: Revealed type is 'builtins.str*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
id = models.AutoField(primary_key=True)
small_int = models.SmallIntegerField()
name = models.CharField(max_length=255)
slug = models.SlugField(max_length=255)
text = models.TextField()
- case: test_model_field_classes_from_existing_locations
main: |
from myapp.models import Booking
booking = Booking()
reveal_type(booking.id) # N: Revealed type is 'builtins.int*'
reveal_type(booking.time_range) # N: Revealed type is 'Any'
reveal_type(booking.some_decimal) # N: Revealed type is 'decimal.Decimal*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.contrib.postgres import fields as pg_fields
from decimal import Decimal
class Booking(models.Model):
id = models.AutoField(primary_key=True)
time_range = pg_fields.DateTimeRangeField(null=False)
some_decimal = models.DecimalField(max_digits=10, decimal_places=5)
- case: test_add_id_field_if_no_primary_key_defined
disable_cache: true
main: |
from myapp.models import User
reveal_type(User().id) # N: Revealed type is 'builtins.int*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
pass
- case: test_do_not_add_id_if_field_with_primary_key_True_defined
disable_cache: true
main: |
from myapp.models import User
reveal_type(User().my_pk) # N: Revealed type is 'builtins.int*'
reveal_type(User().id)
out: |
main:3: note: Revealed type is 'Any'
main:3: error: "User" has no attribute "id"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
my_pk = models.IntegerField(primary_key=True)
- case: blank_and_null_char_field_allows_none
main: |
from myapp.models import MyModel
MyModel(nulltext="")
MyModel(nulltext=None)
MyModel().nulltext=None
reveal_type(MyModel().nulltext) # N: Revealed type is 'Union[builtins.str, None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyModel(models.Model):
nulltext=models.CharField(max_length=1, blank=True, null=True)
- case: blank_and_not_null_charfield_does_not_allow_none
main: |
from myapp.models import MyModel
MyModel(notnulltext=None) # Should allow None in constructor
MyModel(notnulltext="")
MyModel().notnulltext = None # E: Incompatible types in assignment (expression has type "None", variable has type "Union[str, int, Combinable]")
reveal_type(MyModel().notnulltext) # N: Revealed type is 'builtins.str*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyModel(models.Model):
notnulltext=models.CharField(max_length=1, blank=True, null=False)
- case: if_field_called_on_class_return_field_itself
main: |
from myapp.models import MyUser
reveal_type(MyUser.name) # N: Revealed type is 'django.db.models.fields.CharField[Union[builtins.str, builtins.int, django.db.models.expressions.Combinable], builtins.str]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
name = models.CharField(max_length=100)
- case: fields_on_non_model_classes_resolve_to_field_type
main: |
from django.db import models
class MyClass:
myfield: models.IntegerField[int, int]
reveal_type(MyClass.myfield) # N: Revealed type is 'django.db.models.fields.IntegerField[builtins.int, builtins.int]'
reveal_type(MyClass().myfield) # N: Revealed type is 'django.db.models.fields.IntegerField[builtins.int, builtins.int]'
- case: fields_inside_mixins_used_in_model_subclasses_resolved_as_primitives
main: |
from myapp.models import MyModel, AuthMixin
reveal_type(MyModel().username) # N: Revealed type is 'builtins.str*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class AuthMixin(models.Model):
class Meta:
abstract = True
username = models.CharField(max_length=100)
class MyModel(AuthMixin, models.Model):
pass

View File

@@ -0,0 +1,21 @@
- case: generic_foreign_key_could_point_to_any_model_and_is_always_optional
main: |
from myapp.models import Tag, User
myuser = User()
Tag(content_object=None)
Tag(content_object=myuser)
Tag.objects.create(content_object=None)
Tag.objects.create(content_object=myuser)
reveal_type(Tag().content_object) # N: Revealed type is 'Union[Any, None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.contrib.contenttypes import fields
class User(models.Model):
pass
class Tag(models.Model):
content_object = fields.GenericForeignKey()

View File

@@ -0,0 +1,70 @@
- case: nullable_field_with_strict_optional_true
main: |
from myapp.models import MyModel
reveal_type(MyModel().text) # N: Revealed type is 'builtins.str*'
reveal_type(MyModel().text_nullable) # N: Revealed type is 'Union[builtins.str, None]'
MyModel().text = None # E: Incompatible types in assignment (expression has type "None", variable has type "Union[str, int, Combinable]")
MyModel().text_nullable = None
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyModel(models.Model):
text_nullable = models.CharField(max_length=100, null=True)
text = models.CharField(max_length=100)
- case: nullable_array_field
main: |
from myapp.models import MyModel
reveal_type(MyModel().lst) # N: Revealed type is 'Union[builtins.list[builtins.str], None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.contrib.postgres.fields import ArrayField
class MyModel(models.Model):
lst = ArrayField(base_field=models.CharField(max_length=100), null=True)
- case: nullable_foreign_key
main: |
from myapp.models import Publisher, Book
reveal_type(Book().publisher) # N: Revealed type is 'Union[myapp.models.Publisher, None]'
Book().publisher = 11 # E: Incompatible types in assignment (expression has type "int", variable has type "Union[Publisher, Combinable, None]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE, null=True)
- case: nullable_self_foreign_key
main: |
from myapp.models import Inventory
parent = Inventory()
core = Inventory(parent_id=parent.id)
reveal_type(core.parent_id) # N: Revealed type is 'Union[builtins.int, None]'
reveal_type(core.parent) # N: Revealed type is 'Union[myapp.models.Inventory, None]'
Inventory(parent=None)
Inventory(parent_id=None)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Inventory(models.Model):
parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True)

View File

@@ -0,0 +1,35 @@
- case: array_field_descriptor_access
main: |
from myapp.models import User
user = User(array=[])
reveal_type(user.array) # N: Revealed type is 'builtins.list*[Any]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.contrib.postgres.fields import ArrayField
class User(models.Model):
array = ArrayField(base_field=models.Field())
- case: array_field_base_field_parsed_into_generic_typevar
main: |
from myapp.models import User
user = User()
reveal_type(user.members) # N: Revealed type is 'builtins.list*[builtins.int]'
reveal_type(user.members_as_text) # N: Revealed type is 'builtins.list*[builtins.str]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.contrib.postgres.fields import ArrayField
class User(models.Model):
members = ArrayField(base_field=models.IntegerField())
members_as_text = ArrayField(base_field=models.CharField(max_length=255))

View File

@@ -0,0 +1,674 @@
- case: test_foreign_key_field_with_related_name
main: |
from myapp.models import Book, Publisher
book = Book()
reveal_type(book.publisher) # N: Revealed type is 'myapp.models.Publisher*'
publisher = Publisher()
reveal_type(publisher.books) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Book]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE,
related_name='books')
- case: foreign_key_field_creates_attribute_with_underscore_id
main: |
from myapp.models import Book
book = Book()
reveal_type(book.publisher_id) # N: Revealed type is 'builtins.int*'
reveal_type(book.owner_id) # N: Revealed type is 'builtins.int*'
installed_apps:
- django.contrib.auth
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
owner = models.ForeignKey(db_column='model_id', to='auth.User', on_delete=models.CASCADE)
- case: foreign_key_field_different_order_of_params
main: |
from myapp.models import Book, Publisher
book = Book()
reveal_type(book.publisher) # N: Revealed type is 'myapp.models.Publisher*'
reveal_type(book.publisher2) # N: Revealed type is 'myapp.models.Publisher*'
publisher = Publisher()
reveal_type(publisher.books) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Book]'
reveal_type(publisher.books2) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Book]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(on_delete=models.CASCADE, to=Publisher,
related_name='books')
publisher2 = models.ForeignKey(to=Publisher, related_name='books2', on_delete=models.CASCADE)
- case: to_parameter_as_string_with_application_name__model_imported
main: |
from myapp2.models import Book
book = Book()
reveal_type(book.publisher) # N: Revealed type is 'myapp.models.Publisher*'
installed_apps:
- myapp
- myapp2
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
- path: myapp2/__init__.py
- path: myapp2/models.py
content: |
from django.db import models
class Book(models.Model):
publisher = models.ForeignKey(to='myapp.Publisher', on_delete=models.CASCADE)
- case: one_to_one_field_no_related_name
main: |
from myapp.models import User, Profile
reveal_type(User().profile) # N: Revealed type is 'myapp.models.Profile'
reveal_type(Profile().user) # N: Revealed type is 'myapp.models.User*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
pass
class Profile(models.Model):
user = models.OneToOneField(to=User, on_delete=models.CASCADE)
- case: test_circular_dependency_in_imports_with_foreign_key
main: |
from myapp import models
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class App(models.Model):
def method(self) -> None:
reveal_type(self.views) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.View]'
reveal_type(self.members) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Member]'
reveal_type(self.sheets) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Sheet]'
reveal_type(self.profile) # N: Revealed type is 'myapp.models.Profile'
class View(models.Model):
app = models.ForeignKey(to=App, related_name='views', on_delete=models.CASCADE)
class Member(models.Model):
app = models.ForeignKey(related_name='members', on_delete=models.CASCADE, to=App)
class Sheet(models.Model):
app = models.ForeignKey(App, related_name='sheets', on_delete=models.CASCADE)
class Profile(models.Model):
app = models.OneToOneField(App, related_name='profile', on_delete=models.CASCADE)
- case: test_circular_dependency_in_imports_with_string_based
main: |
from myapp.models import View
reveal_type(View().app.views) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.View]'
reveal_type(View().app.unknown)
out: |
main:3: note: Revealed type is 'Any'
main:3: error: "App" has no attribute "unknown"
installed_apps:
- myapp
- myapp2
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from myapp2.models import App
class View(models.Model):
app = models.ForeignKey(to=App, related_name='views', on_delete=models.CASCADE)
- path: myapp2/__init__.py
- path: myapp2/models.py
content: |
from django.db import models
class App(models.Model):
def method(self) -> None:
reveal_type(self.views) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.View]'
- case: models_related_managers_work_with_direct_model_inheritance_and_with_inheritance_from_other_model
main: |
from myapp.models import App
reveal_type(App().views) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.View]'
reveal_type(App().views2) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.View2]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class App(models.Model):
pass
class View(models.Model):
app = models.ForeignKey(to=App, on_delete=models.CASCADE, related_name='views')
class View2(View):
app2 = models.ForeignKey(to=App, on_delete=models.CASCADE, related_name='views2')
- case: models_imported_inside_init_file_foreign_key
main: |
from myapp2.models import View
reveal_type(View().app.views) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp2.models.View]'
installed_apps:
- myapp
- myapp2
files:
- path: myapp/__init__.py
- path: myapp/models/__init__.py
content: |
from .app import App
- path: myapp/models/app.py
content: |
from django.db import models
class App(models.Model):
pass
- path: myapp2/__init__.py
- path: myapp2/models.py
content: |
from django.db import models
from myapp.models import App
class View(models.Model):
app = models.ForeignKey(to='myapp.App', related_name='views', on_delete=models.CASCADE)
- case: models_imported_inside_init_file_one_to_one_field
main: |
from myapp2.models import Profile
reveal_type(Profile().user) # N: Revealed type is 'myapp.models.user.User*'
reveal_type(Profile().user.profile) # N: Revealed type is 'myapp2.models.Profile'
installed_apps:
- myapp
- myapp2
files:
- path: myapp/__init__.py
- path: myapp/models/__init__.py
content: |
from .user import User
- path: myapp/models/user.py
content: |
from django.db import models
class User(models.Model):
pass
- path: myapp2/__init__.py
- path: myapp2/models.py
content: |
from django.db import models
from myapp.models import User
class Profile(models.Model):
user = models.OneToOneField(to='myapp.User', related_name='profile', on_delete=models.CASCADE)
- case: models_triple_circular_reference
main: |
from myapp.models import App
reveal_type(App().owner) # N: Revealed type is 'myapp.models.user.User*'
reveal_type(App().owner.profile) # N: Revealed type is 'myapp.models.profile.Profile'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models/__init__.py
content: |
from .user import User
from .profile import Profile
from .app import App
- path: myapp/models/user.py
content: |
from django.db import models
class User(models.Model):
pass
- path: myapp/models/profile.py
content: |
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(to='myapp.User', related_name='profile', on_delete=models.CASCADE)
- path: myapp/models/app.py
content: |
from django.db import models
class App(models.Model):
owner = models.ForeignKey(to='myapp.User', on_delete=models.CASCADE, related_name='apps')
- case: many_to_many_field_converts_to_queryset_of_model_type
main: |
from myapp.models import App, Member
reveal_type(Member().apps) # N: Revealed type is 'django.db.models.manager.RelatedManager*[myapp.models.App]'
reveal_type(App().members) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Member]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class App(models.Model):
pass
class Member(models.Model):
apps = models.ManyToManyField(to=App, related_name='members')
- case: many_to_many_works_with_string_if_imported
main: |
from myapp.models import Member
reveal_type(Member().apps) # N: Revealed type is 'django.db.models.manager.RelatedManager*[myapp2.models.App]'
installed_apps:
- myapp
- myapp2
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Member(models.Model):
apps = models.ManyToManyField(to='myapp2.App', related_name='members')
- path: myapp2/__init__.py
- path: myapp2/models.py
content: |
from django.db import models
class App(models.Model):
pass
- case: foreign_key_with_self
main: |
from myapp.models import User
reveal_type(User().parent) # N: Revealed type is 'myapp.models.User*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
parent = models.ForeignKey('self', on_delete=models.CASCADE)
- case: many_to_many_with_self
main: |
from myapp.models import User
reveal_type(User().friends) # N: Revealed type is 'django.db.models.manager.RelatedManager*[myapp.models.User]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
friends = models.ManyToManyField('self')
- case: recursively_checking_for_base_model_in_to_parameter
main: |
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class BaseModel(models.Model):
pass
class ParkingSpot(BaseModel):
pass
class Booking(BaseModel):
parking_spot = models.ForeignKey(to=ParkingSpot, null=True, on_delete=models.SET_NULL)
- case: if_no_related_name_is_passed_create_default_related_managers
main: |
from myapp.models import Publisher
reveal_type(Publisher().book_set) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Book]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
- case: underscore_id_attribute_has_set_type_of_primary_key_if_explicit
main: |
import datetime
from myapp.models import Book, Book2
reveal_type(Book().publisher_id) # N: Revealed type is 'builtins.str*'
Book(publisher_id=1)
Book(publisher_id='hello')
Book(publisher_id=datetime.datetime.now()) # E: Incompatible type for "publisher_id" of "Book" (got "datetime", expected "Union[str, int, Combinable, None]")
Book.objects.create(publisher_id=1)
Book.objects.create(publisher_id='hello')
reveal_type(Book2().publisher_id) # N: Revealed type is 'builtins.int*'
Book2(publisher_id=1)
Book2(publisher_id=[]) # E: Incompatible type for "publisher_id" of "Book2" (got "List[Any]", expected "Union[float, int, str, Combinable, None]")
Book2.objects.create(publisher_id=1)
Book2.objects.create(publisher_id=[]) # E: Incompatible type for "publisher_id" of "Book2" (got "List[Any]", expected "Union[float, int, str, Combinable]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
import datetime
class Publisher(models.Model):
mypk = models.CharField(max_length=100, primary_key=True)
class Book(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
class Publisher2(models.Model):
mypk = models.IntegerField(primary_key=True)
class Book2(models.Model):
publisher = models.ForeignKey(to=Publisher2, on_delete=models.CASCADE)
- case: if_model_is_defined_as_name_of_the_class_look_for_it_in_the_same_app
main: |
from myapp.models import Book
reveal_type(Book().publisher) # N: Revealed type is 'myapp.models.publisher.Publisher*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models/__init__.py
content: |
from .publisher import Publisher
from .book import Book
- path: myapp/models/publisher.py
content: |
from django.db import models
class Publisher(models.Model):
pass
- path: myapp/models/book.py
content: |
from django.db import models
class Book(models.Model):
publisher = models.ForeignKey(to='Publisher', on_delete=models.CASCADE)
- case: fail_if_no_model_in_the_same_app_models_init_py
main: |
from myapp.models import Book
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models/__init__.py
content: |
from .book import Book
- path: myapp/models/publisher.py
content: |
from django.db import models
class Publisher(models.Model):
pass
- path: myapp/models/book.py
content: |
from django.db import models
class Book(models.Model):
publisher = models.ForeignKey(to='Publisher', on_delete=models.CASCADE) # E: Cannot find model 'Publisher' referenced in field 'publisher'
- case: test_foreign_key_field_without_backwards_relation
main: |
from myapp.models import Book, Publisher
book = Book()
reveal_type(book.publisher) # N: Revealed type is 'myapp.models.Publisher*'
publisher = Publisher()
reveal_type(publisher.books)
reveal_type(publisher.books2) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Book]'
out: |
main:6: error: "Publisher" has no attribute "books"; maybe "books2"?
main:6: note: Revealed type is 'Any'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE,
related_name='+')
publisher2 = models.ForeignKey(to=Publisher, on_delete=models.CASCADE,
related_name='books2')
- case: to_parameter_could_be_resolved_if_passed_from_settings
main: |
from myapp.models import Book
book = Book()
reveal_type(book.publisher) # N: Revealed type is 'myapp.models.Publisher*'
custom_settings: |
INSTALLED_APPS = ('django.contrib.contenttypes', 'myapp')
BOOK_RELATED_MODEL = 'myapp.Publisher'
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.conf import settings
from django.db import models
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(to=settings.BOOK_RELATED_MODEL, on_delete=models.CASCADE,
related_name='books')
- case: foreign_key_with_custom_app_name
main: |
from myapp.models import MyMain
reveal_type(MyMain().user) # N: Revealed type is 'myapp2.models.MyUser*'
installed_apps:
- myapp
- myapp2.apps.MyApp2Config
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyMain(models.Model):
user = models.ForeignKey('myapp2__user.MyUser', on_delete=models.CASCADE)
- path: myapp2/__init__.py
- path: myapp2/models.py
content: |
from django.db import models
class MyUser(models.Model):
pass
- path: myapp2/apps.py
content: |
from django.apps.config import AppConfig
class MyApp2Config(AppConfig):
name = 'myapp2'
label = 'myapp2__user'
- case: related_field_to_extracted_from_function
main: |
from myapp.models import Profile
reveal_type(Profile().user) # N: Revealed type is 'myapp.models.User*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
pass
def get_user_model_name():
return 'myapp.User'
class Profile(models.Model):
user = models.ForeignKey(to=get_user_model_name(), on_delete=models.CASCADE)
- case: related_manager_name_defined_by_pattern
main: |
from myapp.models import Publisher
reveal_type(Publisher().books) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Book]'
reveal_type(Publisher().articles) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Article]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Entry(models.Model):
class Meta:
abstract = True
publisher = models.ForeignKey(to=Publisher, related_name='%(class)ss', on_delete=models.CASCADE)
class Book(Entry):
pass
class Article(Entry):
pass
- case: test_related_fields_returned_as_descriptors_from_model_class
main: |
from myapp.models import Author, Blog, Publisher, Profile
reveal_type(Author.blogs) # N: Revealed type is 'django.db.models.fields.related_descriptors.ManyToManyDescriptor'
reveal_type(Blog.publisher) # N: Revealed type is 'django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor'
reveal_type(Publisher.profile) # N: Revealed type is 'django.db.models.fields.related_descriptors.ForwardOneToOneDescriptor'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Profile(models.Model):
pass
class Publisher(models.Model):
profile = models.OneToOneField(Profile, on_delete=models.CASCADE)
class Blog(models.Model):
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
class Author(models.Model):
blogs = models.ManyToManyField(Blog)
file = models.FileField()
- case: test_foreign_key_from_superclass_inherits_correctly
main: |
from myapp.models import MyUser, Book, Article, LibraryEntity
reveal_type(Book().registered_by_user) # N: Revealed type is 'myapp.models.MyUser*'
reveal_type(Article().registered_by_user) # N: Revealed type is 'myapp.models.MyUser*'
user = MyUser()
reveal_type(user.book_set) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Book]'
reveal_type(user.article_set) # N: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.Article]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
pass
class LibraryEntity(models.Model):
class Meta:
abstract = True
registered_by_user = models.ForeignKey(MyUser, on_delete=models.CASCADE)
class Book(LibraryEntity):
pass
class Article(LibraryEntity):
pass
- case: foreign_key_relationship_for_models_with_custom_manager
main: |
from myapp.models import Transaction
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class TransactionQuerySet(models.QuerySet):
pass
class Transaction(models.Model):
objects = TransactionQuerySet.as_manager()
def test(self) -> None:
self.transactionlog_set
class TransactionLog(models.Model):
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE)
Transaction().test()
- case: resolve_primary_keys_for_foreign_keys_with_abstract_self_model
main: |
from myapp.models import User
reveal_type(User().parent) # N: Revealed type is 'myapp.models.User*'
reveal_type(User().parent_id) # N: Revealed type is 'builtins.int*'
reveal_type(User().parent2) # N: Revealed type is 'Union[myapp.models.User, None]'
reveal_type(User().parent2_id) # N: Revealed type is 'Union[builtins.int, None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class AbstractUser(models.Model):
parent = models.ForeignKey('self', on_delete=models.CASCADE)
parent2 = models.ForeignKey('self', null=True, on_delete=models.CASCADE)
class Meta:
abstract = True
class User(AbstractUser):
pass
- case: related_manager_is_a_subclass_of_default_manager
main: |
from myapp.models import User
reveal_type(User().orders) # N: Revealed type is 'myapp.models.Order_RelatedManager'
reveal_type(User().orders.get()) # N: Revealed type is 'myapp.models.Order*'
reveal_type(User().orders.manager_method()) # N: Revealed type is 'builtins.int'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
pass
class OrderManager(models.Manager):
def manager_method(self) -> int:
pass
class Order(models.Model):
objects = OrderManager()
user = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='orders')

View File

@@ -0,0 +1,47 @@
- case: queryset_basic_methods_return_type
main: |
from myapp.models import Blog
qs = Blog.objects.all()
reveal_type(qs) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.Blog]'
reveal_type(qs.get(id=1)) # N: Revealed type is 'myapp.models.Blog*'
reveal_type(iter(qs)) # N: Revealed type is 'typing.Iterator[myapp.models.Blog*]'
reveal_type(qs.iterator()) # N: Revealed type is 'typing.Iterator[myapp.models.Blog*]'
reveal_type(qs.first()) # N: Revealed type is 'Union[myapp.models.Blog*, None]'
reveal_type(qs.earliest()) # N: Revealed type is 'myapp.models.Blog*'
reveal_type(qs[0]) # N: Revealed type is 'myapp.models.Blog*'
reveal_type(qs[:9]) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.Blog]'
reveal_type(qs.in_bulk()) # N: Revealed type is 'builtins.dict[Any, myapp.models.Blog*]'
# .dates / .datetimes
reveal_type(Blog.objects.dates("created_at", "day")) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Blog*, datetime.date]'
reveal_type(Blog.objects.datetimes("created_at", "day")) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Blog*, datetime.datetime]'
# AND-ing QuerySets
reveal_type(Blog.objects.all() & Blog.objects.all()) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.Blog]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Blog(models.Model):
created_at = models.DateTimeField()
- case: queryset_missing_method
main: |
from myapp.models import User
reveal_type(User.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.User]'
User.objects.not_existing_method() # E: "Manager[User]" has no attribute "not_existing_method"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
pass

View File

@@ -0,0 +1,256 @@
- case: filtering_with_proper_types
main: |
from myapp.models import User
User.objects.filter(username='maksim')
User.objects.get(username='maksim')
User.objects.exclude(username='maksim')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
username = models.CharField(max_length=100)
- case: no_such_field_for_filter
main: |
from myapp.models import User
User.objects.filter(unknown_field=True) # E: Cannot resolve keyword 'unknown_field' into field. Choices are: id
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
pass
- case: filter_with_invalid_type
main: |
from myapp.models import User
User.objects.filter(age=User()) # E: Incompatible type for lookup 'age': (got "User", expected "Union[str, int]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.db import models
class User(models.Model):
age = models.IntegerField()
- case: filter_with_multiple_fields
main: |
from myapp.models import User
User.objects.filter(age=User(), gender=User())
installed_apps:
- myapp
out: |
main:2: error: Incompatible type for lookup 'age': (got "User", expected "Union[str, int]")
main:2: error: Incompatible type for lookup 'gender': (got "User", expected "Union[str, int]")
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
age = models.IntegerField()
gender = models.IntegerField()
- case: valid_filter_with_lookup
main: |
from myapp.models import User
User.objects.filter(username__contains='hello')
User.objects.filter(age__gt=1)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
username = models.CharField(max_length=100)
age = models.IntegerField()
- case: invalid_filter_with_lookup
main: |
from myapp.models import User
User.objects.filter(username__contains=1) # E: Incompatible type for lookup 'username__contains': (got "int", expected "str")
User.objects.filter(username__icontains=1) # E: Incompatible type for lookup 'username__icontains': (got "int", expected "str")
User.objects.filter(username__isnull=1) # E: Incompatible type for lookup 'username__isnull': (got "int", expected "bool")
User.objects.filter(created_at=User()) # E: Incompatible type for lookup 'created_at': (got "User", expected "Union[str, datetime]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
username = models.CharField(max_length=100)
age = models.IntegerField()
created_at = models.DateTimeField()
- case: strings_are_allowed_for_exact_for_dates
main: |
from myapp.models import User
User.objects.filter(created_at='2018')
User.objects.filter(created_at__exact='2018')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
created_at = models.DateTimeField()
- case: related_model_foreign_key_lookups
main: |
from myapp.models import Blog, Publisher
blog = Blog()
publisher = Publisher()
Blog.objects.filter(publisher=publisher)
Blog.objects.filter(publisher_id=1)
Blog.objects.filter(publisher__id=1)
Blog.objects.filter(publisher=blog) # E: Incompatible type for lookup 'publisher': (got "Blog", expected "Union[Publisher, int, None]")
Blog.objects.filter(publisher_id=blog) # E: Incompatible type for lookup 'publisher_id': (got "Blog", expected "Union[str, int]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Blog(models.Model):
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE, related_name='blogs')
- case: related_model_reverse_foreign_key_lookup
main: |
from myapp.models import Blog, Publisher
blog = Blog()
publisher = Publisher()
Publisher.objects.filter(blogs=Blog())
Publisher.objects.filter(blogs__id=1)
Publisher.objects.filter(blogs=publisher) # E: Incompatible type for lookup 'blogs': (got "Publisher", expected "Union[Blog, int, None]")
Publisher.objects.filter(blogs__id=publisher) # E: Incompatible type for lookup 'blogs__id': (got "Publisher", expected "Union[str, int]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Blog(models.Model):
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE, related_name='blogs')
- case: many_to_many_lookups
main: |
from myapp.models import Book, Author
book = Book()
author = Author()
Book.objects.filter(authors=author)
Book.objects.filter(authors=book) # E: Incompatible type for lookup 'authors': (got "Book", expected "Union[Author, int, None]")
Book.objects.filter(authors='hello') # E: Incompatible type for lookup 'authors': (got "str", expected "Union[Author, int, None]")
Author.objects.filter(books=book)
Author.objects.filter(books=author) # E: Incompatible type for lookup 'books': (got "Author", expected "Union[Book, int, None]")
Author.objects.filter(books='hello') # E: Incompatible type for lookup 'books': (got "str", expected "Union[Book, int, None]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Book(models.Model):
pass
class Author(models.Model):
books = models.ManyToManyField(Book, related_name='authors')
- case: one_to_one_lookups
main: |
from myapp.models import User, Profile
user = User()
profile = Profile()
User.objects.filter(profile=profile)
User.objects.filter(profile=user) # E: Incompatible type for lookup 'profile': (got "User", expected "Union[Profile, int, None]")
User.objects.filter(profile='hello') # E: Incompatible type for lookup 'profile': (got "str", expected "Union[Profile, int, None]")
Profile.objects.filter(user=user)
Profile.objects.filter(user=profile) # E: Incompatible type for lookup 'user': (got "Profile", expected "Union[User, int, None]")
Profile.objects.filter(user='hello') # E: Incompatible type for lookup 'user': (got "str", expected "Union[User, int, None]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
pass
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
# TODO
- case: f_expression_simple_case
main: |
from myapp.models import User
from django.db import models
User.objects.filter(username=models.F('username2'))
User.objects.filter(username=models.F('age'))
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
username = models.TextField()
username2 = models.TextField()
age = models.IntegerField()
# TODO
- case: f_expression_with_expression_math_is_not_supported
main: |
from myapp.models import User
from django.db import models
User.objects.filter(username=models.F('username2') + 'hello')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
username = models.TextField()
username2 = models.TextField()
age = models.IntegerField()

View File

@@ -0,0 +1,181 @@
- case: from_queryset_with_base_manager
main: |
from myapp.models import MyModel
reveal_type(MyModel().objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
reveal_type(MyModel().objects.get()) # N: Revealed type is 'myapp.models.MyModel*'
reveal_type(MyModel().objects.queryset_method()) # N: Revealed type is 'builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.db.models.manager import BaseManager
class ModelQuerySet(models.QuerySet):
def queryset_method(self) -> str:
return 'hello'
NewManager = BaseManager.from_queryset(ModelQuerySet)
class MyModel(models.Model):
objects = NewManager()
- case: from_queryset_with_manager
main: |
from myapp.models import MyModel
reveal_type(MyModel().objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
reveal_type(MyModel().objects.get()) # N: Revealed type is 'myapp.models.MyModel*'
reveal_type(MyModel().objects.queryset_method()) # N: Revealed type is 'builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class ModelQuerySet(models.QuerySet):
def queryset_method(self) -> str:
return 'hello'
NewManager = models.Manager.from_queryset(ModelQuerySet)
class MyModel(models.Model):
objects = NewManager()
- case: from_queryset_returns_intersection_of_manager_and_queryset
main: |
from myapp.models import MyModel, NewManager
reveal_type(NewManager()) # N: Revealed type is 'myapp.models.NewManager'
reveal_type(MyModel.objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
reveal_type(MyModel.objects.get()) # N: Revealed type is 'Any'
reveal_type(MyModel.objects.manager_only_method()) # N: Revealed type is 'builtins.int'
reveal_type(MyModel.objects.manager_and_queryset_method()) # N: Revealed type is 'builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class ModelBaseManager(models.Manager):
def manager_only_method(self) -> int:
return 1
class ModelQuerySet(models.QuerySet):
def manager_and_queryset_method(self) -> str:
return 'hello'
NewManager = ModelBaseManager.from_queryset(ModelQuerySet)
class MyModel(models.Model):
objects = NewManager()
- case: from_queryset_with_class_name_provided
main: |
from myapp.models import MyModel, NewManager
reveal_type(NewManager()) # N: Revealed type is 'myapp.models.NewManager'
reveal_type(MyModel.objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
reveal_type(MyModel.objects.get()) # N: Revealed type is 'Any'
reveal_type(MyModel.objects.manager_only_method()) # N: Revealed type is 'builtins.int'
reveal_type(MyModel.objects.manager_and_queryset_method()) # N: Revealed type is 'builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class ModelBaseManager(models.Manager):
def manager_only_method(self) -> int:
return 1
class ModelQuerySet(models.QuerySet):
def manager_and_queryset_method(self) -> str:
return 'hello'
NewManager = ModelBaseManager.from_queryset(ModelQuerySet, class_name='NewManager')
class MyModel(models.Model):
objects = NewManager()
- case: from_queryset_with_class_inheritance
main: |
from myapp.models import MyModel
reveal_type(MyModel().objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
reveal_type(MyModel().objects.get()) # N: Revealed type is 'myapp.models.MyModel*'
reveal_type(MyModel().objects.queryset_method()) # N: Revealed type is 'builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.db.models.manager import BaseManager
class BaseQuerySet(models.QuerySet):
def queryset_method(self) -> str:
return 'hello'
class ModelQuerySet(BaseQuerySet):
pass
NewManager = BaseManager.from_queryset(ModelQuerySet)
class MyModel(models.Model):
objects = NewManager()
- case: from_queryset_with_manager_in_another_directory_and_imports
main: |
from myapp.models import MyModel
reveal_type(MyModel().objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
reveal_type(MyModel().objects.get()) # N: Revealed type is 'myapp.models.MyModel*'
reveal_type(MyModel().objects.queryset_method) # N: Revealed type is 'def (param: Union[builtins.str, None] =) -> Union[builtins.str, None]'
reveal_type(MyModel().objects.queryset_method('str')) # N: Revealed type is 'Union[builtins.str, None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from myapp.managers import NewManager
class MyModel(models.Model):
objects = NewManager()
- path: myapp/managers.py
content: |
from typing import Optional
from django.db import models
class ModelQuerySet(models.QuerySet):
def queryset_method(self, param: Optional[str] = None) -> Optional[str]:
return param
NewManager = models.Manager.from_queryset(ModelQuerySet)
- case: from_queryset_with_inherited_manager_and_typing_no_return
disable_cache: true
main: |
from myapp.models import MyModel
reveal_type(MyModel().objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
reveal_type(MyModel().objects.get()) # N: Revealed type is 'myapp.models.MyModel*'
reveal_type(MyModel().objects.base_queryset_method) # N: Revealed type is 'def (param: Union[builtins.int, builtins.str]) -> <nothing>'
reveal_type(MyModel().objects.base_queryset_method(2)) # N: Revealed type is '<nothing>'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from myapp.managers import NewManager
class MyModel(models.Model):
objects = NewManager()
- path: myapp/managers.py
content: |
from django.db import models
from myapp.base_queryset import BaseQuerySet
class ModelQuerySet(BaseQuerySet):
pass
NewManager = models.Manager.from_queryset(ModelQuerySet)
- path: myapp/base_queryset.py
content: |
from typing import NoReturn, Union
from django.db import models
class BaseQuerySet(models.QuerySet):
def base_queryset_method(self, param: Union[int, str]) -> NoReturn:
raise ValueError

View File

@@ -0,0 +1,126 @@
- case: queryset_values_method_returns_typeddict
main: |
from myapp.models import Blog
values = Blog.objects.values('num_posts', 'text').get()
reveal_type(values) # N: Revealed type is 'TypedDict({'num_posts': builtins.int, 'text': builtins.str})'
reveal_type(values["num_posts"]) # N: Revealed type is 'builtins.int'
reveal_type(values["text"]) # N: Revealed type is 'builtins.str'
values_pk = Blog.objects.values('pk').get()
reveal_type(values_pk) # N: Revealed type is 'TypedDict({'pk': builtins.int})'
reveal_type(values_pk["pk"]) # N: Revealed type is 'builtins.int'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Blog(models.Model):
num_posts = models.IntegerField()
text = models.CharField(max_length=100)
- case: queryset_values_all_values
main: |
from myapp.models import Blog
all_values_dict = Blog.objects.values().get()
reveal_type(all_values_dict) # N: Revealed type is 'TypedDict({'id': builtins.int, 'num_posts': builtins.int, 'text': builtins.str})'
reveal_type(all_values_dict["id"]) # N: Revealed type is 'builtins.int'
reveal_type(all_values_dict["num_posts"]) # N: Revealed type is 'builtins.int'
reveal_type(all_values_dict["text"]) # N: Revealed type is 'builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Blog(models.Model):
num_posts = models.IntegerField()
text = models.CharField(max_length=100)
- case: queryset_foreign_key_object_always_a_primary_key
main: |
from myapp.models import Blog
values1 = Blog.objects.values('publisher').get()
reveal_type(values1) # N: Revealed type is 'TypedDict({'publisher': builtins.int})'
reveal_type(values1['publisher']) # N: Revealed type is 'builtins.int'
values2 = Blog.objects.values('publisher_id').get()
reveal_type(values2) # N: Revealed type is 'TypedDict({'publisher_id': builtins.int})'
reveal_type(values2["publisher_id"]) # N: Revealed type is 'builtins.int'
# all values return _id version
all_values = Blog.objects.values().get()
reveal_type(all_values) # N: Revealed type is 'TypedDict({'id': builtins.int, 'publisher_id': builtins.int})'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Blog(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
- case: values_with_related_model_fields
main: |
from myapp.models import Entry
values = Entry.objects.values('blog__num_articles', 'blog__publisher__name').get()
reveal_type(values) # N: Revealed type is 'TypedDict({'blog__num_articles': builtins.int, 'blog__publisher__name': builtins.str})'
pk_values = Entry.objects.values('blog__pk', 'blog__publisher__pk').get()
reveal_type(pk_values) # N: Revealed type is 'TypedDict({'blog__pk': builtins.int, 'blog__publisher__pk': builtins.int})'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=100)
class Blog(models.Model):
num_articles = models.IntegerField()
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
- case: select_all_related_model_values_for_every_current_value
main: |
from myapp.models import Publisher
related_model_values = Publisher.objects.values('id', 'blog__name').get()
reveal_type(related_model_values) # N: Revealed type is 'TypedDict({'id': builtins.int, 'blog__name': builtins.str})'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Blog(models.Model):
name = models.CharField(max_length=100)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
- case: values_of_many_to_many_field
main: |
from myapp.models import Author, Book
reveal_type(Book.objects.values('authors')) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Book, TypedDict({'authors': builtins.int})]'
reveal_type(Author.objects.values('books')) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Author, TypedDict({'books': builtins.int})]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Author(models.Model):
pass
class Book(models.Model):
authors = models.ManyToManyField(Author, related_name='books')

View File

@@ -0,0 +1,243 @@
- case: values_list_simple_field_returns_queryset_of_tuples
main: |
from myapp.models import MyUser
reveal_type(MyUser.objects.values_list('name').get()) # N: Revealed type is 'Tuple[builtins.str]'
reveal_type(MyUser.objects.values_list('id', 'name').get()) # N: Revealed type is 'Tuple[builtins.int, builtins.str]'
values_tuple = MyUser.objects.values_list('name', 'age').get()
reveal_type(values_tuple[0]) # N: Revealed type is 'builtins.str'
reveal_type(values_tuple[1]) # N: Revealed type is 'builtins.int'
# no fields specified return all fields
all_values_tuple = MyUser.objects.values_list().get()
reveal_type(all_values_tuple) # N: Revealed type is 'Tuple[builtins.int, builtins.str, builtins.int]'
# pk as field
pk_values = MyUser.objects.values_list('pk').get()
reveal_type(pk_values) # N: # N: Revealed type is 'Tuple[builtins.int]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
- case: values_list_related_model_fields
main: |
from myapp.models import Post, Blog
values_tuple = Post.objects.values_list('blog', 'blog__num_posts', 'blog__publisher', 'blog__publisher__name').get()
reveal_type(values_tuple[0]) # N: Revealed type is 'myapp.models.Blog'
reveal_type(values_tuple[1]) # N: Revealed type is 'builtins.int'
reveal_type(values_tuple[2]) # N: Revealed type is 'myapp.models.Publisher'
reveal_type(values_tuple[3]) # N: Revealed type is 'builtins.str'
reverse_fields_list = Blog.objects.values_list('post__text').get()
reveal_type(reverse_fields_list) # N: Revealed type is 'Tuple[builtins.str]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=100)
class Blog(models.Model):
num_posts = models.IntegerField()
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
class Post(models.Model):
text = models.CharField(max_length=100)
blog = models.ForeignKey(to=Blog, on_delete=models.CASCADE)
- case: values_list_flat_true_methods
main: |
from myapp.models import MyUser, MyUser2
reveal_type(MyUser.objects.values_list('name', flat=True).get()) # N: Revealed type is 'builtins.str*'
reveal_type(MyUser.objects.values_list('name', 'age', flat=True).get())
# flat=True without specified fields returns primary key values
reveal_type(MyUser.objects.values_list(flat=True)[0]) # N: Revealed type is 'builtins.int*'
reveal_type(MyUser2.objects.values_list(flat=True)[0]) # N: Revealed type is 'builtins.str*'
out: |
main:3: error: 'flat' is not valid when 'values_list' is called with more than one field
main:3: note: Revealed type is 'Any'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
class MyUser2(models.Model):
name = models.CharField(max_length=100, primary_key=True)
- case: values_list_named_true
main: |
from myapp.models import MyUser
values_named_tuple = MyUser.objects.values_list('name', 'age', named=True).get()
reveal_type(values_named_tuple) # N: Revealed type is 'Tuple[builtins.str, builtins.int, fallback=main.Row]'
reveal_type(values_named_tuple.name) # N: Revealed type is 'builtins.str'
reveal_type(values_named_tuple.age) # N: Revealed type is 'builtins.int'
# no fields specified, returns all fields namedtuple
all_values_named_tuple = MyUser.objects.values_list(named=True).get()
reveal_type(all_values_named_tuple.id) # N: Revealed type is 'builtins.int'
reveal_type(all_values_named_tuple.name) # N: Revealed type is 'builtins.str'
reveal_type(all_values_named_tuple.age) # N: Revealed type is 'builtins.int'
reveal_type(all_values_named_tuple.is_admin) # N: Revealed type is 'builtins.bool'
# pk as field
pk_values = MyUser.objects.values_list('pk', named=True).get()
reveal_type(pk_values) # N: Revealed type is 'Tuple[builtins.int, fallback=main.Row2]'
reveal_type(pk_values.pk) # N: # N: Revealed type is 'builtins.int'
# values_list(named=True) inside function
def func() -> None:
from myapp.models import MyUser
reveal_type(MyUser.objects.values_list('name', named=True).get()) # N: Revealed type is 'Tuple[builtins.str, fallback=main.Row3]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
is_admin = models.BooleanField()
- case: values_list_flat_true_named_true_error
main: |
from myapp.models import MyUser
reveal_type(MyUser.objects.values_list('name', flat=True, named=True).get())
out: |
main:2: error: 'flat' and 'named' can't be used together
main:2: note: Revealed type is 'Any'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
name = models.CharField(max_length=100)
- case: invalid_lookups
main: |
from myapp.models import Blog
reveal_type(Blog.objects.values_list('unknown').get())
reveal_type(Blog.objects.values_list('unknown', flat=True).get())
reveal_type(Blog.objects.values_list('unknown', named=True).get())
reveal_type(Blog.objects.values_list('publisher__unknown').get())
out: |
main:2: error: Cannot resolve keyword 'unknown' into field. Choices are: id, publisher, publisher_id
main:2: note: Revealed type is 'Any'
main:3: error: Cannot resolve keyword 'unknown' into field. Choices are: id, publisher, publisher_id
main:3: note: Revealed type is 'Any'
main:4: error: Cannot resolve keyword 'unknown' into field. Choices are: id, publisher, publisher_id
main:4: note: Revealed type is 'Any'
main:5: note: Revealed type is 'Tuple[Any]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Blog(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
- case: named_true_with_related_model_fields
main: |
from myapp.models import Entry, Blog
values = Entry.objects.values_list('blog__num_articles', 'blog__publisher__name', named=True).get()
reveal_type(values.blog__num_articles) # N: Revealed type is 'builtins.int'
reveal_type(values.blog__publisher__name) # N: Revealed type is 'builtins.str'
pk_values = Entry.objects.values_list('blog__pk', 'blog__publisher__pk', named=True).get()
reveal_type(pk_values.blog__pk) # N: Revealed type is 'builtins.int'
reveal_type(pk_values.blog__publisher__pk) # N: Revealed type is 'builtins.int'
# reverse relation
reverse_values = Blog.objects.values_list('entry__text', named=True).get()
reveal_type(reverse_values.entry__text) # N: Revealed type is 'builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=100)
class Blog(models.Model):
num_articles = models.IntegerField()
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
class Entry(models.Model):
text = models.CharField(max_length=100)
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
- case: values_list_flat_true_with_ids
main: |
from myapp.models import Blog, Publisher
reveal_type(Blog.objects.values_list('id', flat=True)) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Blog, builtins.int]'
reveal_type(Blog.objects.values_list('publisher_id', flat=True)) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Blog, builtins.int]'
# is Iterable[int]
reveal_type(list(Blog.objects.values_list('id', flat=True))) # N: Revealed type is 'builtins.list[builtins.int*]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Blog(models.Model):
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE)
- case: subclass_of_queryset_has_proper_typings_on_methods
main: |
from myapp.models import TransactionQuerySet
reveal_type(TransactionQuerySet()) # N: Revealed type is 'myapp.models.TransactionQuerySet'
reveal_type(TransactionQuerySet().values()) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Transaction, TypedDict({'id': builtins.int, 'total': builtins.int})]'
reveal_type(TransactionQuerySet().values_list()) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Transaction, Tuple[builtins.int, builtins.int]]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class TransactionQuerySet(models.QuerySet['Transaction']):
pass
class Transaction(models.Model):
total = models.IntegerField()
- case: values_list_of_many_to_many_field
main: |
from myapp.models import Author, Book
reveal_type(Book.objects.values_list('authors')) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Book, Tuple[builtins.int]]'
reveal_type(Author.objects.values_list('books')) # N: Revealed type is 'django.db.models.query.ValuesQuerySet[myapp.models.Author, Tuple[builtins.int]]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Author(models.Model):
pass
class Book(models.Model):
authors = models.ManyToManyField(Author, related_name='books')

View File

@@ -0,0 +1,359 @@
- case: test_every_model_has_objects_queryset_available
main: |
from myapp.models import User
reveal_type(User.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.User]'
reveal_type(User.objects.get()) # N: Revealed type is 'myapp.models.User*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
pass
- case: every_model_has_its_own_objects_queryset
main: |
from myapp.models import Parent, Child
reveal_type(Parent.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.Parent]'
reveal_type(Child.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.Child]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Parent(models.Model):
pass
class Child(Parent):
pass
- case: test_model_objects_attribute_present_in_case_of_model_cls_passed_as_generic_parameter
main: |
from myapp.models import Base, MyModel
base_instance = Base(MyModel)
reveal_type(base_instance.model_cls._default_manager) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyModel]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
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) # N: Revealed type is 'django.db.models.manager.BaseManager[django.db.models.base.Model]'
class MyModel(models.Model):
pass
class Child(Base[MyModel]):
def method(self) -> None:
reveal_type(self.model_cls._default_manager) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyModel]'
- case: if_custom_manager_defined_it_is_set_to_default_manager
main: |
from myapp.models import MyModel
reveal_type(MyModel._default_manager) # N: Revealed type is 'myapp.models.CustomManager[myapp.models.MyModel]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
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']()
- case: if_default_manager_name_is_passed_set_default_manager_to_it
main: |
from myapp.models import MyModel
reveal_type(MyModel._default_manager) # N: Revealed type is 'myapp.models.Manager2[myapp.models.MyModel]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
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']()
- case: test_leave_as_is_if_objects_is_set_and_fill_typevars_with_outer_class
main: |
from myapp.models import MyUser
reveal_type(MyUser.objects) # N: Revealed type is 'myapp.models.UserManager[myapp.models.MyUser]'
reveal_type(MyUser.objects.get()) # N: Revealed type is 'myapp.models.MyUser*'
reveal_type(MyUser.objects.get_or_404()) # N: Revealed type is 'myapp.models.MyUser'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class UserManager(models.Manager['MyUser']):
def get_or_404(self) -> 'MyUser':
pass
class MyUser(models.Model):
objects = UserManager()
- case: model_imported_from_different_file
main: |
from myapp.models import Inventory, Band
reveal_type(Inventory.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.main.Inventory]'
reveal_type(Band.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.Band]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models/__init__.py
content: |
from django.db import models
from .main import Inventory
class Band(models.Model):
pass
- path: myapp/models/main.py
content: |
from django.db import models
class Inventory(models.Model):
pass
- case: managers_that_defined_on_other_models_do_not_influence
main: |
from myapp.models import AbstractPerson, Book
reveal_type(AbstractPerson.abstract_persons) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.AbstractPerson]'
reveal_type(Book.published_objects) # N: Revealed type is 'myapp.models.PublishedBookManager[myapp.models.Book]'
Book.published_objects.create(title='hello')
reveal_type(Book.annotated_objects) # N: Revealed type is 'myapp.models.AnnotatedBookManager[myapp.models.Book]'
Book.annotated_objects.create(title='hello')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
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()
- case: managers_inherited_from_abstract_classes_multiple_inheritance
main: |
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
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
- case: model_has_a_manager_of_the_same_type
main: |
from myapp.models import UnrelatedModel, MyModel
reveal_type(UnrelatedModel.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.UnrelatedModel]'
reveal_type(UnrelatedModel.objects.first()) # N: Revealed type is 'Union[myapp.models.UnrelatedModel*, None]'
reveal_type(MyModel.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyModel]'
reveal_type(MyModel.objects.first()) # N: Revealed type is 'Union[myapp.models.MyModel*, None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class UnrelatedModel(models.Model):
objects = models.Manager['UnrelatedModel']()
class MyModel(models.Model):
pass
- case: manager_without_annotation_of_the_model_gets_it_from_outer_one
main: |
from myapp.models import UnrelatedModel2, MyModel2
reveal_type(UnrelatedModel2.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.UnrelatedModel2]'
reveal_type(UnrelatedModel2.objects.first()) # N: Revealed type is 'Union[myapp.models.UnrelatedModel2*, None]'
reveal_type(MyModel2.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyModel2]'
reveal_type(MyModel2.objects.first()) # N: Revealed type is 'Union[myapp.models.MyModel2*, None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class UnrelatedModel2(models.Model):
objects = models.Manager()
class MyModel2(models.Model):
pass
- case: inherited_manager_has_the_proper_type_of_model
main: |
from myapp.models import ParentOfMyModel3, MyModel3
reveal_type(ParentOfMyModel3.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.ParentOfMyModel3]'
reveal_type(ParentOfMyModel3.objects.first()) # N: Revealed type is 'Union[myapp.models.ParentOfMyModel3*, None]'
reveal_type(MyModel3.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyModel3]'
reveal_type(MyModel3.objects.first()) # N: Revealed type is 'Union[myapp.models.MyModel3*, None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class ParentOfMyModel3(models.Model):
objects = models.Manager()
class MyModel3(ParentOfMyModel3):
pass
- case: inheritance_with_explicit_type_on_child_manager
main: |
from myapp.models import ParentOfMyModel4, MyModel4
reveal_type(ParentOfMyModel4.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.ParentOfMyModel4]'
reveal_type(ParentOfMyModel4.objects.first()) # N: Revealed type is 'Union[myapp.models.ParentOfMyModel4*, None]'
reveal_type(MyModel4.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyModel4]'
reveal_type(MyModel4.objects.first()) # N: Revealed type is 'Union[myapp.models.MyModel4*, None]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class ParentOfMyModel4(models.Model):
objects = models.Manager()
class MyModel4(ParentOfMyModel4):
objects = models.Manager['MyModel4']()
# TODO: make it work someday
#- case: inheritance_of_two_models_with_custom_objects_manager
# main: |
# from myapp.models import MyBaseUser, MyUser
# reveal_type(MyBaseUser.objects) # N: Revealed type is 'myapp.models.MyBaseManager[myapp.models.MyBaseUser]'
# reveal_type(MyBaseUser.objects.get()) # N: Revealed type is 'myapp.models.MyBaseUser'
#
# reveal_type(MyUser.objects) # N: Revealed type is 'myapp.models.MyManager[myapp.models.MyUser]'
# reveal_type(MyUser.objects.get()) # N: Revealed type is 'myapp.models.MyUser'
# installed_apps:
# - myapp
# files:
# - path: myapp/__init__.py
# - path: myapp/models.py
# content: |
# from django.db import models
#
# class MyBaseManager(models.Manager):
# pass
# class MyBaseUser(models.Model):
# objects = MyBaseManager()
#
# class MyManager(models.Manager):
# pass
# class MyUser(MyBaseUser):
# objects = MyManager()
- case: custom_manager_returns_proper_model_types
main: |
from myapp.models import User
reveal_type(User.objects) # N: Revealed type is 'myapp.models.User_MyManager2[myapp.models.User]'
reveal_type(User.objects.select_related()) # N: Revealed type is 'myapp.models.User_MyManager2[myapp.models.User]'
reveal_type(User.objects.get()) # N: Revealed type is 'myapp.models.User*'
reveal_type(User.objects.get_instance()) # N: Revealed type is 'builtins.int'
reveal_type(User.objects.get_instance_untyped('hello')) # N: Revealed type is 'Any'
from myapp.models import ChildUser
reveal_type(ChildUser.objects) # N: Revealed type is 'myapp.models.ChildUser_MyManager2[myapp.models.ChildUser]'
reveal_type(ChildUser.objects.select_related()) # N: Revealed type is 'myapp.models.ChildUser_MyManager2[myapp.models.ChildUser]'
reveal_type(ChildUser.objects.get()) # N: Revealed type is 'myapp.models.ChildUser*'
reveal_type(ChildUser.objects.get_instance()) # N: Revealed type is 'builtins.int'
reveal_type(ChildUser.objects.get_instance_untyped('hello')) # N: Revealed type is 'Any'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyManager(models.Manager):
def get_instance(self) -> int:
pass
def get_instance_untyped(self, name):
pass
class User(models.Model):
objects = MyManager()
class ChildUser(models.Model):
objects = MyManager()
- case: custom_manager_annotate_method_before_type_declaration
main: |
from myapp.models import ModelA, ModelB, ManagerA
reveal_type(ModelA.objects) # N: Revealed type is 'myapp.models.ModelA_ManagerA1[myapp.models.ModelA]'
reveal_type(ModelA.objects.do_something) # N: Revealed type is 'def (other_obj: myapp.models.ModelB) -> builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class ManagerA(models.Manager):
def do_something(self, other_obj: "ModelB") -> str:
return 'test'
class ModelA(models.Model):
title = models.TextField()
objects = ManagerA()
class ModelB(models.Model):
movie = models.TextField()

View File

@@ -0,0 +1,28 @@
- case: contrib_auth_model_fields
main: |
from django.contrib.auth.models import User
reveal_type(User().username) # N: Revealed type is 'builtins.str*'
reveal_type(User().password) # N: Revealed type is 'builtins.str*'
reveal_type(User().first_name) # N: Revealed type is 'builtins.str*'
reveal_type(User().last_name) # N: Revealed type is 'builtins.str*'
reveal_type(User().email) # N: Revealed type is 'builtins.str*'
reveal_type(User().is_staff) # N: Revealed type is 'builtins.bool*'
reveal_type(User().is_active) # N: Revealed type is 'builtins.bool*'
reveal_type(User().date_joined) # N: Revealed type is 'datetime.datetime*'
reveal_type(User().last_login) # N: Revealed type is 'Union[datetime.datetime, None]'
reveal_type(User().is_authenticated) # N: Revealed type is 'Literal[True]'
reveal_type(User().is_anonymous) # N: Revealed type is 'Literal[False]'
from django.contrib.auth.models import AnonymousUser
reveal_type(AnonymousUser().is_authenticated) # N: Revealed type is 'Literal[False]'
reveal_type(AnonymousUser().is_anonymous) # N: Revealed type is 'Literal[True]'
from django.contrib.auth.models import Permission
reveal_type(Permission().name) # N: Revealed type is 'builtins.str*'
reveal_type(Permission().codename) # N: Revealed type is 'builtins.str*'
from django.contrib.auth.models import PermissionsMixin
reveal_type(PermissionsMixin().is_superuser) # N: Revealed type is 'builtins.bool*'
from django.contrib.auth.models import Group
reveal_type(Group().name) # N: Revealed type is 'builtins.str*'

View File

@@ -0,0 +1,113 @@
- case: default_manager_create_is_typechecked
main: |
from myapp.models import User
User.objects.create(pk=1, name='Max', age=10)
User.objects.create(age=[]) # E: Incompatible type for "age" of "User" (got "List[Any]", expected "Union[float, int, str, Combinable]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
- case: model_recognises_parent_attributes
main: |
from myapp.models import Child
Child.objects.create(name='Maxim', lastname='Maxim2')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Parent(models.Model):
name = models.CharField(max_length=100)
class Child(Parent):
lastname = models.CharField(max_length=100)
- case: deep_multiple_inheritance_with_create
main: |
from myapp.models import Child4
Child4.objects.create(name1='n1', name2='n2', value=1, value4=4)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Parent1(models.Model):
name1 = models.CharField(max_length=50)
class Parent2(models.Model):
id2 = models.AutoField(primary_key=True)
name2 = models.CharField(max_length=50)
class Child1(Parent1, Parent2):
value = models.IntegerField()
class Child4(Child1):
value4 = models.IntegerField()
- case: optional_id_fields_for_create_is_error_if_not_autofield
main: |
from myapp.models import Publisher, Book
Book.objects.create(id=None) # E: Incompatible type for "id" of "Book" (got "None", expected "Union[float, int, str, Combinable]")
Book.objects.create(publisher=None) # E: Incompatible type for "publisher" of "Book" (got "None", expected "Union[Publisher, Combinable]")
Book.objects.create(publisher_id=None) # E: Incompatible type for "publisher_id" of "Book" (got "None", expected "Union[Combinable, int, str]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class Book(models.Model):
id = models.IntegerField(primary_key=True)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
- case: none_for_primary_key_is_allowed_if_field_is_autogenerated
main: |
from myapp.models import Book
Book.objects.create(id=None)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Book(models.Model):
pass
- case: when_default_for_primary_key_is_specified_allow_none_to_be_set
main: |
from myapp.models import MyModel
MyModel(id=None)
MyModel.objects.create(id=None)
from myapp.models import MyModel2
MyModel2(id=None)
MyModel2.objects.create(id=None) # E: Incompatible type for "id" of "MyModel2" (got "None", expected "Union[float, int, str, Combinable]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
def return_int():
return 0
class MyModel(models.Model):
id = models.IntegerField(primary_key=True, default=return_int)
class MyModel2(models.Model):
id = models.IntegerField(primary_key=True)

View File

@@ -0,0 +1,56 @@
- case: if_field_has_choices_set_model_has_get_FIELDNAME_display_method
main: |
from myapp.models import MyUser
user = MyUser(name='user', gender='M')
user.get_name_display() # E: "MyUser" has no attribute "get_name_display"; maybe "get_gender_display"?
reveal_type(user.get_gender_display()) # N: Revealed type is 'builtins.str'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
class MyUser(models.Model):
name = models.CharField(max_length=100)
gender = models.CharField(max_length=100, choices=GENDER_CHOICES)
- case: date_datetime_fields_have_get_next_by_get_previous_by
main: |
from myapp.models import MyUser
reveal_type(MyUser().get_next_by_date()) # N: Revealed type is 'myapp.models.MyUser'
reveal_type(MyUser().get_next_by_datetime()) # N: Revealed type is 'myapp.models.MyUser'
reveal_type(MyUser().get_previous_by_date()) # N: Revealed type is 'myapp.models.MyUser'
reveal_type(MyUser().get_previous_by_datetime()) # N: Revealed type is 'myapp.models.MyUser'
# accept arbitrary kwargs
MyUser().get_next_by_date(arg1=1, arg2=2)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
date = models.DateField()
datetime = models.DateTimeField()
- case: get_next_by_get_previous_by_absent_if_null_true
main: |
from myapp.models import MyUser
MyUser().get_next_by_date() # E: "MyUser" has no attribute "get_next_by_date"
MyUser().get_previous_by_date() # E: "MyUser" has no attribute "get_previous_by_date"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
date = models.DateField(null=True)

View File

@@ -0,0 +1,115 @@
- case: test_meta_nested_class_allows_subclassing_in_multiple_inheritance
main: |
from typing import Any
from django.db import models
class Mixin1(models.Model):
class Meta:
abstract = True
class Mixin2(models.Model):
class Meta:
abstract = True
class User(Mixin1, Mixin2):
pass
- case: test_inheritance_from_abstract_model_does_not_fail_if_field_with_id_exists
main: |
from django.db import models
class Abstract(models.Model):
class Meta:
abstract = True
class User(Abstract):
id = models.AutoField(primary_key=True)
- case: test_typechecking_for_model_subclasses
main: |
from myapp.models import A, B, C
def service(a: A) -> int:
pass
b_instance = B()
service(b_instance) # E: Argument 1 to "service" has incompatible type "B"; expected "A"
a_instance = A()
c_instance = C()
service(a_instance)
service(c_instance)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class A(models.Model):
pass
class B(models.Model):
b_attr = 1
pass
class C(A):
pass
- case: fail_if_no_such_attribute_on_model
main: |
from myapp.models import B
b_instance = B()
reveal_type(b_instance.b_attr) # N: Revealed type is 'builtins.int'
reveal_type(b_instance.non_existent_attribute)
b_instance.non_existent_attribute = 2
out: |
main:5: note: Revealed type is 'Any'
main:5: error: "B" has no attribute "non_existent_attribute"
main:6: error: "B" has no attribute "non_existent_attribute"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class B(models.Model):
b_attr = 1
pass
- case: fields_recognized_if_base_model_is_subclass_of_models_model
main: |
from myapp.models import User
reveal_type(User().username) # N: Revealed type is 'builtins.str*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from myapp.utils import MyBaseModel
class User(MyBaseModel):
username = models.CharField(max_length=100)
- path: myapp/utils.py
content: |
from django.db.models import Model
class MyBaseModel(Model):
pass
- case: django_contrib_gis_base_model_mixin_inheritance
main: |
from myapp.models import User
reveal_type(User().name) # N: Revealed type is 'builtins.str*'
reveal_type(User().updated_at) # N: Revealed type is 'datetime.datetime*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.contrib.gis.db import models as gis_models
class Mixin1(gis_models.Model):
class Meta:
abstract = True
class Mixin2(gis_models.Model):
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class User(Mixin1, Mixin2):
name = models.TextField()

View File

@@ -0,0 +1,257 @@
- case: arguments_to_init_unexpected_attributes
main: |
from myapp.models import MyUser
user = MyUser(name=1, age=12)
out: |
main:2: error: Unexpected attribute "name" for model "MyUser"
main:2: error: Unexpected attribute "age" for model "MyUser"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
pass
- case: plain_function_which_returns_model
main: |
from myapp.models import MyUser
def func(i: int) -> MyUser:
pass
func("hello") # E: Argument 1 to "func" has incompatible type "str"; expected "int"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
pass
- case: arguments_to_init_from_class_incompatible_type
main: |
from myapp.models import MyUser
user = MyUser(name='hello', age=[])
out: |
main:2: error: Incompatible type for "age" of "MyUser" (got "List[Any]", expected "Union[float, int, str, Combinable]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
- case: arguments_to_init_combined_from_base_classes
main: |
from myapp.models import BaseUser, ChildUser
user = ChildUser(name='Max', age=12, lastname='Lastname')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class BaseUser(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
class ChildUser(BaseUser):
lastname = models.CharField(max_length=100)
- case: fields_from_abstract_user_propagate_to_init
main: |
from myapp.models import MyUser
user = MyUser(name='Maxim')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class AbstractUser(models.Model):
class Meta:
abstract = True
name = models.CharField(max_length=100)
class MyUser(AbstractUser):
pass
- case: pk_refers_to_primary_key_and_could_be_passed_to_init
main: |
from myapp.models import MyUser1, MyUser2
user2 = MyUser1(pk='hello')
user3 = MyUser2(pk=1, name='maxim')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser1(models.Model):
mypk = models.CharField(primary_key=True)
class MyUser2(models.Model):
name = models.CharField(max_length=100)
- case: typechecking_of_pk
main: |
from myapp.models import MyUser1
user = MyUser1(pk=[]) # E: Incompatible type for "pk" of "MyUser1" (got "List[Any]", expected "Union[float, int, str, Combinable, None]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser1(models.Model):
mypk = models.IntegerField(primary_key=True)
- case: set_foreign_key_by_its_primary_key
main: |
from datetime import datetime
now = datetime.now()
from myapp.models import Publisher, PublisherDatetime, Book
Book(publisher_id=1, publisher_dt_id=now)
Book(publisher_id=[], publisher_dt_id=now) # E: Incompatible type for "publisher_id" of "Book" (got "List[Any]", expected "Union[Combinable, int, str, None]")
Book(publisher_id=1, publisher_dt_id=1) # E: Incompatible type for "publisher_dt_id" of "Book" (got "int", expected "Union[str, date, Combinable, None]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class PublisherDatetime(models.Model):
dt_pk = models.DateTimeField(primary_key=True)
class Book(models.Model):
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
publisher_dt = models.ForeignKey(PublisherDatetime, on_delete=models.CASCADE)
- case: setting_value_to_an_array_of_ints
main: |
from typing import List, Tuple
from myapp.models import MyModel
array_val: Tuple[int, ...] = (1,)
MyModel(array=array_val)
array_val2: List[int] = [1]
MyModel(array=array_val2)
class NotAValid:
pass
array_val3: List[NotAValid] = [NotAValid()]
MyModel(array=array_val3) # E: Incompatible type for "array" of "MyModel" (got "List[NotAValid]", expected "Union[Sequence[Union[float, int, str, Combinable]], Combinable]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from typing import List, Tuple
from django.db import models
from django.contrib.postgres.fields import ArrayField
class MyModel(models.Model):
array = ArrayField(base_field=models.IntegerField())
- case: if_no_explicit_primary_key_id_can_be_passed
main: |
from myapp.models import MyModel
MyModel(id=1, name='maxim')
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=100)
- case: arguments_can_be_passed_as_positionals
main: |
from myapp.models import MyModel, MyModel2
MyModel(1)
MyModel2(1, 12)
MyModel2(1, []) # E: Incompatible type for "name" of "MyModel2" (got "List[Any]", expected "Union[float, int, str, Combinable]")
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyModel(models.Model):
pass
class MyModel2(models.Model):
name = models.IntegerField()
- case: charfield_with_integer_choices
main: |
from myapp.models import MyModel
MyModel(day=1)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyModel(models.Model):
day = models.CharField(max_length=3, choices=((1, 'Fri'), (2, 'Sat')))
- case: optional_id_fields_allowed_in_init
main: |
from myapp.models import Book, Publisher
Book(id=None)
Book(publisher=None)
Book(publisher_id=None)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
name = models.CharField(primary_key=True, max_length=100)
class Book(models.Model):
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
- case: init_in_abstract_model_classmethod_should_not_throw_error_for_valid_fields
main: |
from myapp.models import MyModel
MyModel.base_init()
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class AbstractModel(models.Model):
class Meta:
abstract = True
text = models.CharField(max_length=100)
@classmethod
def base_init(cls) -> 'AbstractModel':
return cls(text='mytext')
class MyModel(AbstractModel):
pass

View File

@@ -0,0 +1,58 @@
- case: meta_attribute_has_a_type_of_current_model
main: |
from myapp.models import MyUser
reveal_type(MyUser._meta) # N: Revealed type is 'django.db.models.options.Options[myapp.models.MyUser]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
pass
- case: get_field_returns_proper_field_type
main: |
from myapp.models import MyUser
reveal_type(MyUser._meta.get_field('base_name')) # N: Revealed type is 'django.db.models.fields.CharField[Any, Any]'
reveal_type(MyUser._meta.get_field('name')) # N: Revealed type is 'django.db.models.fields.CharField[Any, Any]'
reveal_type(MyUser._meta.get_field('age')) # N: Revealed type is 'django.db.models.fields.IntegerField[Any, Any]'
reveal_type(MyUser._meta.get_field('unknown'))
reveal_type(MyUser._meta.get_field('to_user')) # N: Revealed type is 'django.db.models.fields.related.ForeignKey[Any, Any]'
out: |
main:5: note: Revealed type is 'Any'
main:5: error: MyUser has no field named 'unknown'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyBaseUser(models.Model):
base_name = models.CharField(max_length=100)
class MyUser(MyBaseUser):
name = models.CharField(max_length=100)
age = models.IntegerField()
to_user = models.ForeignKey('self', on_delete=models.SET_NULL)
- case: get_field_with_abstract_inheritance
main: |
from myapp.models import AbstractModel
class MyModel(AbstractModel):
pass
reveal_type(MyModel._meta.get_field('field')) # N: Revealed type is 'Any'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django.contrib.postgres.fields import ArrayField
class AbstractModel(models.Model):
class Meta:
abstract = True
class MyModel(AbstractModel):
field = ArrayField(models.IntegerField(), default=[])

View File

@@ -0,0 +1,21 @@
- case: foreign_key_to_proxy_model_accepts_first_non_proxy_model
main: |
from myapp.models import Blog, Publisher, PublisherProxy
Blog(publisher=Publisher())
Blog.objects.create(publisher=Publisher())
Blog().publisher = Publisher()
reveal_type(Blog().publisher) # N: Revealed type is 'myapp.models.PublisherProxy*'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class Publisher(models.Model):
pass
class PublisherProxy(Publisher):
class Meta:
proxy = True
class Blog(models.Model):
publisher = models.ForeignKey(to=PublisherProxy, on_delete=models.CASCADE)

View File

@@ -0,0 +1,14 @@
- case: state_attribute_has_a_type_of_model_state
main: |
from myapp.models import MyUser
user = MyUser(pk=1)
reveal_type(user._state) # N: Revealed type is 'django.db.models.base.ModelState'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
pass

View File

@@ -0,0 +1,12 @@
- case: testcase_client_attr
main: |
from django.test.testcases import TestCase
class ExampleTestCase(TestCase):
def test_method(self) -> None:
reveal_type(self.client) # N: Revealed type is 'django.test.client.Client'
resp = self.client.post('/url', {'doit': 'srs'}, 'application/json', False, True, extra='value')
reveal_type(resp.status_code) # N: Revealed type is 'builtins.int'
# Attributes monkey-patched by test Client class:
resp.json()
reveal_type(resp.wsgi_request) # N: Revealed type is 'django.core.handlers.wsgi.WSGIRequest'

View File

@@ -0,0 +1,67 @@
- case: pyproject_toml_config
main: |
from myapp.models import MyModel
mymodel = MyModel(user_id=1)
reveal_type(mymodel.id) # N: Revealed type is 'builtins.int*'
reveal_type(mymodel.user) # N: Revealed type is 'django.contrib.auth.models.User*'
reveal_type(mymodel.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyModel]'
mypy_config: |
[mypy.plugins.django-stubs]
django_settings_module = mysettings
custom_settings: |
SECRET_KEY = '1'
INSTALLED_APPS = ('django.contrib.contenttypes', 'django.contrib.auth', 'myapp')
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from typing import TYPE_CHECKING
from django.db import models
class MyModel(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
if TYPE_CHECKING:
reveal_type(MyModel().user) # N: Revealed type is 'django.contrib.auth.models.User*'
- case: generate_pyproject_toml_and_settings_file_from_installed_apps_key
main: |
from myapp.models import MyModel
mymodel = MyModel(user_id=1)
reveal_type(mymodel.id) # N: Revealed type is 'builtins.int*'
installed_apps:
- django.contrib.auth
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyModel(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
- case: add_mypy_path_to_package_search
main: |
import extra_module
mypy_config: |
[mypy]
mypy_path = ./extras
[mypy.plugins.django-stubs]
django_settings_module = mysettings
files:
- path: extras/extra_module.py
content: |
def extra_fn():
pass
- case: add_mypypath_env_var_to_package_search
main: |
import extra_module
mypy_config: |
[mypy.plugins.django-stubs]
django_settings_module = mysettings
env:
- MYPYPATH=./extras
files:
- path: extras/extra_module.py
content: |
def extra_fn():
pass

View File

@@ -0,0 +1,70 @@
- case: no_incompatible_meta_nested_class_false_positive
main: |
from django import forms
from myapp.models import Article, Category
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = '__all__'
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = '__all__'
class CompositeForm(ArticleForm, CategoryForm):
pass
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
from django import forms
class Article(models.Model):
pass
class Category(models.Model):
pass
- case: formview_methods_on_forms_return_proper_types
main: |
from typing import Any
from django import forms
from django.views.generic.edit import FormView
class MyForm(forms.ModelForm):
pass
class MyForm2(forms.ModelForm):
pass
class MyView(FormView):
form_class = MyForm
def post(self, request, *args: Any, **kwds: Any):
form_class = self.get_form_class()
reveal_type(form_class) # N: Revealed type is 'Type[main.MyForm]'
reveal_type(self.get_form(None)) # N: Revealed type is 'main.MyForm'
reveal_type(self.get_form()) # N: Revealed type is 'main.MyForm'
reveal_type(self.get_form(form_class)) # N: Revealed type is 'main.MyForm'
reveal_type(self.get_form(MyForm2)) # N: Revealed type is 'main.MyForm2'
- case: updateview_form_valid_has_form_save
main: |
from django import forms
from django.views.generic.edit import UpdateView
class MyForm(forms.ModelForm):
pass
class MyView(UpdateView):
form_class = MyForm
def form_valid(self, form: forms.BaseModelForm):
reveal_type(form.save) # N: Revealed type is 'def (commit: builtins.bool =) -> Any'
- case: successmessagemixin_compatible_with_formmixin
main: |
from django.views.generic.edit import FormMixin
from django.contrib.messages.views import SuccessMessageMixin
class FormFirstView(FormMixin, SuccessMessageMixin):
pass
class SuccessMessageFirstView(FormMixin, SuccessMessageMixin):
pass

View File

@@ -0,0 +1,62 @@
- case: transaction_atomic_contextmanager
main: |
from django.db import transaction
with transaction.atomic():
pass
with transaction.atomic(using="mydb"):
pass
with transaction.atomic(using="mydb", savepoint=False):
pass
- case: transaction_atomic_decorator
main: |
from django.db import transaction
@transaction.atomic()
def decorated_func(param1: str, param2: int) -> bool:
pass
# Ensure that the function's type is preserved
reveal_type(decorated_func) # N: Revealed type is 'def (param1: builtins.str, param2: builtins.int) -> builtins.bool'
@transaction.atomic(using="mydb")
def decorated_func_using(param1: str, param2: int) -> bool:
pass
# Ensure that the function's type is preserved
reveal_type(decorated_func_using) # N: Revealed type is 'def (param1: builtins.str, param2: builtins.int) -> builtins.bool'
class ClassWithAtomicMethod:
# Bare decorator
@transaction.atomic
def atomic_method1(self, abc: int) -> str:
pass
@transaction.atomic(savepoint=True)
def atomic_method2(self):
pass
@transaction.atomic(using="db", savepoint=True)
def atomic_method3(self, myparam: str) -> int:
pass
ClassWithAtomicMethod().atomic_method1("abc") # E: Argument 1 to "atomic_method1" of "ClassWithAtomicMethod" has incompatible type "str"; expected "int"
# Ensure that the method's type is preserved
reveal_type(ClassWithAtomicMethod().atomic_method1) # N: Revealed type is 'def (abc: builtins.int) -> builtins.str'
# Ensure that the method's type is preserved
reveal_type(ClassWithAtomicMethod().atomic_method3) # N: Revealed type is 'def (myparam: builtins.str) -> builtins.int'
- case: mark_safe_decorator_and_function
main: |
from django.utils.safestring import mark_safe
s = 'hello'
reveal_type(mark_safe(s)) # N: Revealed type is 'django.utils.safestring.SafeText'
reveal_type(mark_safe(s) + mark_safe(s)) # N: Revealed type is 'django.utils.safestring.SafeText'
reveal_type(s + mark_safe(s)) # N: Revealed type is 'builtins.str'
s += mark_safe(s)
reveal_type(s) # N: Revealed type is 'builtins.str'
ms = mark_safe(s)
ms += mark_safe(s)
reveal_type(ms) # N: Revealed type is 'django.utils.safestring.SafeText'
@mark_safe
def func(s: str) -> str:
pass
reveal_type(func) # N: Revealed type is 'def (s: builtins.str) -> builtins.str'

View File

@@ -0,0 +1,442 @@
- case: import_all_modules
main: |
import django.apps
import django.apps.config
import django.apps.registry
import django.conf.global_settings
import django.conf.locale
import django.conf.urls
import django.conf.urls.i18n
import django.conf.urls.static
import django.contrib.admin.actions
import django.contrib.admin.apps
import django.contrib.admin.checks
import django.contrib.admin.decorators
import django.contrib.admin.filters
import django.contrib.admin.forms
import django.contrib.admin.helpers
import django.contrib.admin.models
import django.contrib.admin.options
import django.contrib.admin.sites
import django.contrib.admin.templatetags
import django.contrib.admin.templatetags.admin_list
import django.contrib.admin.templatetags.admin_modify
import django.contrib.admin.templatetags.admin_static
import django.contrib.admin.templatetags.admin_urls
import django.contrib.admin.templatetags.base
import django.contrib.admin.templatetags.log
import django.contrib.admin.tests
import django.contrib.admin.utils
import django.contrib.admin.views
import django.contrib.admin.views.autocomplete
import django.contrib.admin.views.decorators
import django.contrib.admin.views.main
import django.contrib.admin.widgets
import django.contrib.admindocs
import django.contrib.admindocs.middleware
import django.contrib.admindocs.urls
import django.contrib.admindocs.utils
import django.contrib.admindocs.views
import django.contrib.auth.admin
import django.contrib.auth.apps
import django.contrib.auth.backends
import django.contrib.auth.base_user
import django.contrib.auth.checks
import django.contrib.auth.context_processors
import django.contrib.auth.decorators
import django.contrib.auth.forms
import django.contrib.auth.handlers
import django.contrib.auth.handlers.modwsgi
import django.contrib.auth.hashers
import django.contrib.auth.management.commands
import django.contrib.auth.management.commands.changepassword
import django.contrib.auth.management.commands.createsuperuser
import django.contrib.auth.middleware
import django.contrib.auth.mixins
import django.contrib.auth.models
import django.contrib.auth.password_validation
import django.contrib.auth.signals
import django.contrib.auth.tokens
import django.contrib.auth.urls
import django.contrib.auth.validators
import django.contrib.auth.views
import django.contrib.contenttypes.admin
import django.contrib.contenttypes.apps
import django.contrib.contenttypes.checks
import django.contrib.contenttypes.fields
import django.contrib.contenttypes.forms
import django.contrib.contenttypes.management.commands
import django.contrib.contenttypes.management.commands.remove_stale_contenttypes
import django.contrib.contenttypes.models
import django.contrib.contenttypes.views
import django.contrib.flatpages.forms
import django.contrib.flatpages.middleware
import django.contrib.flatpages.models
import django.contrib.flatpages.sitemaps
import django.contrib.flatpages.templatetags
import django.contrib.flatpages.templatetags.flatpages
import django.contrib.flatpages.urls
import django.contrib.flatpages.views
import django.contrib.gis.db.models
import django.contrib.gis.db.models.fields
import django.contrib.humanize.templatetags
import django.contrib.humanize.templatetags.humanize
import django.contrib.messages.api
import django.contrib.messages.constants
import django.contrib.messages.context_processors
import django.contrib.messages.middleware
import django.contrib.messages.storage
import django.contrib.messages.storage.base
import django.contrib.messages.storage.cookie
import django.contrib.messages.storage.fallback
import django.contrib.messages.storage.session
import django.contrib.messages.utils
import django.contrib.messages.views
import django.contrib.postgres.aggregates
import django.contrib.postgres.aggregates.general
import django.contrib.postgres.aggregates.mixins
import django.contrib.postgres.aggregates.statistics
import django.contrib.postgres.constraints
import django.contrib.postgres.fields
import django.contrib.postgres.fields.array
import django.contrib.postgres.fields.citext
import django.contrib.postgres.fields.hstore
import django.contrib.postgres.fields.jsonb
import django.contrib.postgres.fields.mixins
import django.contrib.postgres.fields.ranges
import django.contrib.postgres.functions
import django.contrib.postgres.indexes
import django.contrib.postgres.lookups
import django.contrib.postgres.operations
import django.contrib.postgres.search
import django.contrib.postgres.signals
import django.contrib.postgres.validators
import django.contrib.redirects
import django.contrib.redirects.middleware
import django.contrib.redirects.models
import django.contrib.sessions.backends
import django.contrib.sessions.backends.base
import django.contrib.sessions.backends.cache
import django.contrib.sessions.backends.cached_db
import django.contrib.sessions.backends.db
import django.contrib.sessions.backends.file
import django.contrib.sessions.backends.signed_cookies
import django.contrib.sessions.base_session
import django.contrib.sessions.exceptions
import django.contrib.sessions.management.commands
import django.contrib.sessions.management.commands.clearsessions
import django.contrib.sessions.middleware
import django.contrib.sessions.models
import django.contrib.sessions.serializers
import django.contrib.sitemaps.management.commands
import django.contrib.sitemaps.management.commands.ping_google
import django.contrib.sitemaps.views
import django.contrib.sites
import django.contrib.sites.apps
import django.contrib.sites.management
import django.contrib.sites.managers
import django.contrib.sites.middleware
import django.contrib.sites.models
import django.contrib.sites.requests
import django.contrib.sites.shortcuts
import django.contrib.staticfiles.apps
import django.contrib.staticfiles.checks
import django.contrib.staticfiles.finders
import django.contrib.staticfiles.handlers
import django.contrib.staticfiles.management.commands
import django.contrib.staticfiles.management.commands.collectstatic
import django.contrib.staticfiles.management.commands.findstatic
import django.contrib.staticfiles.management.commands.runserver
import django.contrib.staticfiles.storage
import django.contrib.staticfiles.templatetags
import django.contrib.staticfiles.templatetags.staticfiles
import django.contrib.staticfiles.testing
import django.contrib.staticfiles.urls
import django.contrib.staticfiles.utils
import django.contrib.staticfiles.views
import django.contrib.syndication
import django.contrib.syndication.views
import django.core.cache.backends
import django.core.cache.backends.base
import django.core.cache.backends.db
import django.core.cache.backends.dummy
import django.core.cache.backends.filebased
import django.core.cache.backends.locmem
import django.core.cache.backends.memcached
import django.core.cache.utils
import django.core.checks.caches
import django.core.checks.database
import django.core.checks.messages
import django.core.checks.model_checks
import django.core.checks.registry
import django.core.checks.security
import django.core.checks.security.base
import django.core.checks.security.csrf
import django.core.checks.security.sessions
import django.core.checks.templates
import django.core.checks.translation
import django.core.checks.urls
import django.core.exceptions
import django.core.files
import django.core.files.base
import django.core.files.images
import django.core.files.locks
import django.core.files.move
import django.core.files.storage
import django.core.files.temp
import django.core.files.uploadedfile
import django.core.files.uploadhandler
import django.core.files.utils
import django.core.handlers
import django.core.handlers.base
import django.core.handlers.exception
import django.core.handlers.wsgi
import django.core.mail.backends
import django.core.mail.backends.base
import django.core.mail.message
import django.core.mail.utils
import django.core.management.base
import django.core.management.color
import django.core.management.commands
import django.core.management.commands.dumpdata
import django.core.management.commands.loaddata
import django.core.management.commands.makemessages
import django.core.management.commands.runserver
import django.core.management.commands.testserver
import django.core.management.sql
import django.core.management.templates
import django.core.management.utils
import django.core.paginator
import django.core.serializers
import django.core.serializers.base
import django.core.serializers.json
import django.core.serializers.python
import django.core.servers
import django.core.servers.basehttp
import django.core.signals
import django.core.signing
import django.core.validators
import django.core.wsgi
import django.db.backends.base
import django.db.backends.base.base
import django.db.backends.base.client
import django.db.backends.base.creation
import django.db.backends.base.features
import django.db.backends.base.introspection
import django.db.backends.base.operations
import django.db.backends.base.schema
import django.db.backends.base.validation
import django.db.backends.ddl_references
import django.db.backends.dummy
import django.db.backends.dummy.base
import django.db.backends.mysql
import django.db.backends.mysql.client
import django.db.backends.postgresql
import django.db.backends.postgresql.base
import django.db.backends.postgresql.client
import django.db.backends.postgresql.creation
import django.db.backends.postgresql.operations
import django.db.backends.signals
import django.db.backends.sqlite3
import django.db.backends.sqlite3.base
import django.db.backends.sqlite3.creation
import django.db.backends.sqlite3.features
import django.db.backends.sqlite3.introspection
import django.db.backends.sqlite3.operations
import django.db.backends.sqlite3.schema
import django.db.backends.utils
import django.db.migrations.autodetector
import django.db.migrations.exceptions
import django.db.migrations.executor
import django.db.migrations.graph
import django.db.migrations.loader
import django.db.migrations.migration
import django.db.migrations.operations
import django.db.migrations.operations.base
import django.db.migrations.operations.fields
import django.db.migrations.operations.models
import django.db.migrations.operations.special
import django.db.migrations.operations.utils
import django.db.migrations.optimizer
import django.db.migrations.questioner
import django.db.migrations.recorder
import django.db.migrations.serializer
import django.db.migrations.state
import django.db.migrations.topological_sort
import django.db.migrations.utils
import django.db.migrations.writer
import django.db.models.aggregates
import django.db.models.base
import django.db.models.constraints
import django.db.models.deletion
import django.db.models.expressions
import django.db.models.enums
import django.db.models.fields
import django.db.models.fields.files
import django.db.models.fields.mixins
import django.db.models.fields.proxy
import django.db.models.fields.related
import django.db.models.fields.related_descriptors
import django.db.models.fields.related_lookups
import django.db.models.fields.reverse_related
import django.db.models.functions
import django.db.models.functions.comparison
import django.db.models.functions.datetime
import django.db.models.functions.math
import django.db.models.functions.mixins
import django.db.models.functions.text
import django.db.models.functions.window
import django.db.models.indexes
import django.db.models.lookups
import django.db.models.manager
import django.db.models.options
import django.db.models.query
import django.db.models.query_utils
import django.db.models.signals
import django.db.models.sql
import django.db.models.sql.compiler
import django.db.models.sql.constants
import django.db.models.sql.datastructures
import django.db.models.sql.query
import django.db.models.sql.subqueries
import django.db.models.sql.where
import django.db.models.utils
import django.db.transaction
import django.db.utils
import django.dispatch
import django.dispatch.dispatcher
import django.forms
import django.forms.boundfield
import django.forms.fields
import django.forms.forms
import django.forms.formsets
import django.forms.models
import django.forms.renderers
import django.forms.utils
import django.forms.widgets
import django.http
import django.http.cookie
import django.http.multipartparser
import django.http.request
import django.http.response
import django.middleware
import django.middleware.cache
import django.middleware.clickjacking
import django.middleware.common
import django.middleware.csrf
import django.middleware.gzip
import django.middleware.http
import django.middleware.locale
import django.middleware.security
import django.shortcuts
import django.template.backends
import django.template.backends.base
import django.template.backends.django
import django.template.backends.dummy
import django.template.backends.jinja2
import django.template.backends.utils
import django.template.base
import django.template.context
import django.template.context_processors
import django.template.defaultfilters
import django.template.defaulttags
import django.template.engine
import django.template.exceptions
import django.template.library
import django.template.loader
import django.template.loader_tags
import django.template.loaders
import django.template.loaders.app_directories
import django.template.loaders.base
import django.template.loaders.cached
import django.template.loaders.filesystem
import django.template.loaders.locmem
import django.template.response
import django.template.smartif
import django.template.utils
import django.templatetags
import django.templatetags.cache
import django.templatetags.i18n
import django.templatetags.l10n
import django.templatetags.static
import django.templatetags.tz
import django.test
import django.test.client
import django.test.html
import django.test.runner
import django.test.selenium
import django.test.signals
import django.test.testcases
import django.test.utils
import django.urls
import django.urls.base
import django.urls.conf
import django.urls.converters
import django.urls.exceptions
import django.urls.resolvers
import django.urls.utils
import django.utils._os
import django.utils.archive
import django.utils.autoreload
import django.utils.baseconv
import django.utils.cache
import django.utils.crypto
import django.utils.datastructures
import django.utils.dateformat
import django.utils.dateparse
import django.utils.dates
import django.utils.datetime_safe
import django.utils.deconstruct
import django.utils.decorators
import django.utils.deprecation
import django.utils.duration
import django.utils.encoding
import django.utils.feedgenerator
import django.utils.formats
import django.utils.functional
import django.utils.hashable
import django.utils.html
import django.utils.http
import django.utils.inspect
import django.utils.ipv6
import django.utils.itercompat
import django.utils.jslex
import django.utils.log
import django.utils.lorem_ipsum
import django.utils.module_loading
import django.utils.numberformat
import django.utils.regex_helper
import django.utils.safestring
import django.utils.six
import django.utils.termcolors
import django.utils.text
import django.utils.timesince
import django.utils.timezone
import django.utils.topological_sort
import django.utils.translation
import django.utils.translation.reloader
import django.utils.translation.template
import django.utils.translation.trans_null
import django.utils.translation.trans_real
import django.utils.tree
import django.utils.version
import django.utils.xmlutils
import django.views.csrf
import django.views.debug
import django.views.decorators
import django.views.decorators.cache
import django.views.decorators.clickjacking
import django.views.decorators.csrf
import django.views.decorators.debug
import django.views.decorators.gzip
import django.views.decorators.http
import django.views.decorators.vary
import django.views.defaults
import django.views.generic
import django.views.generic.base
import django.views.generic.dates
import django.views.generic.detail
import django.views.generic.edit
import django.views.generic.list
import django.views.i18n
import django.views.static

View File

@@ -0,0 +1,54 @@
- case: request_object_has_user_of_type_auth_user_model
disable_cache: true
main: |
from django.http.request import HttpRequest
reveal_type(HttpRequest().user) # N: Revealed type is 'Union[myapp.models.MyUser, django.contrib.auth.models.AnonymousUser]'
# check that other fields work ok
reveal_type(HttpRequest().method) # N: Revealed type is 'Union[builtins.str, None]'
custom_settings: |
INSTALLED_APPS = ('django.contrib.contenttypes', 'django.contrib.auth', 'myapp')
AUTH_USER_MODEL='myapp.MyUser'
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
pass
- case: request_object_user_can_be_descriminated
disable_cache: true
main: |
from django.http.request import HttpRequest
request = HttpRequest()
reveal_type(request.user) # N: Revealed type is 'Union[django.contrib.auth.models.User, django.contrib.auth.models.AnonymousUser]'
if not request.user.is_anonymous:
reveal_type(request.user) # N: Revealed type is 'django.contrib.auth.models.User'
if request.user.is_authenticated:
reveal_type(request.user) # N: Revealed type is 'django.contrib.auth.models.User'
custom_settings: |
INSTALLED_APPS = ('django.contrib.contenttypes', 'django.contrib.auth')
- case: subclass_request_not_changed_user_type
disable_cache: true
main: |
from django.http.request import HttpRequest
class MyRequest(HttpRequest):
foo: int # Just do something
request = MyRequest()
reveal_type(request.user) # N: Revealed type is 'Union[django.contrib.auth.models.User, django.contrib.auth.models.AnonymousUser]'
custom_settings: |
INSTALLED_APPS = ('django.contrib.contenttypes', 'django.contrib.auth')
- case: subclass_request_changed_user_type
disable_cache: true
main: |
from django.http.request import HttpRequest
from django.contrib.auth.models import User
class MyRequest(HttpRequest):
user: User # Override the type of user
request = MyRequest()
reveal_type(request.user) # N: Revealed type is 'django.contrib.auth.models.User'
custom_settings: |
INSTALLED_APPS = ('django.contrib.contenttypes', 'django.contrib.auth')

View File

@@ -0,0 +1,50 @@
- case: settings_loaded_from_different_files
disable_cache: true
main: |
from django.conf import settings
# standard settings
reveal_type(settings.AUTH_USER_MODEL) # N: Revealed type is 'builtins.str'
reveal_type(settings.ROOT_DIR) # N: Revealed type is 'builtins.str'
reveal_type(settings.APPS_DIR) # N: Revealed type is 'pathlib.Path*'
reveal_type(settings.NUMBERS) # N: Revealed type is 'builtins.list[builtins.str*]'
reveal_type(settings.DICT) # N: Revealed type is 'builtins.dict[Any, Any]'
custom_settings: |
from base import *
SECRET_KEY = 112233
NUMBERS = ['one', 'two']
DICT = {} # type: ignore
files:
- path: base.py
content: |
from pathlib import Path
ROOT_DIR = '/etc'
APPS_DIR = Path(ROOT_DIR)
- case: global_settings_are_always_loaded
main: |
from django.conf import settings
reveal_type(settings.AUTH_USER_MODEL) # N: Revealed type is 'builtins.str'
reveal_type(settings.AUTHENTICATION_BACKENDS) # N: Revealed type is 'typing.Sequence[builtins.str]'
installed_apps: []
- case: fail_if_there_is_no_setting
main: |
from django.conf import settings
reveal_type(settings.NOT_EXISTING)
out: |
main:2: note: Revealed type is 'Any'
main:2: error: 'Settings' object has no attribute 'NOT_EXISTING'
- case: override_default_setting_with_different_type_in_the_different_module
custom_settings: |
from settings.basic_settings import *
main: |
from django.conf import settings
reveal_type(settings.MEDIA_ROOT) # N: Revealed type is 'pathlib.Path*'
reveal_type(settings.MEDIA_ROOT / 'part') # N: Revealed type is 'pathlib.Path*'
files:
- path: settings/__init__.py
- path: settings/basic_settings.py
content: |
from pathlib import Path
MEDIA_ROOT = Path()

View File

@@ -0,0 +1,59 @@
- case: get_object_or_404_returns_proper_types
main: |
from django.shortcuts import get_object_or_404, get_list_or_404
from myapp.models import MyModel
reveal_type(get_object_or_404(MyModel)) # N: Revealed type is 'myapp.models.MyModel*'
reveal_type(get_object_or_404(MyModel.objects)) # N: Revealed type is 'myapp.models.MyModel*'
reveal_type(get_object_or_404(MyModel.objects.get_queryset())) # N: Revealed type is 'myapp.models.MyModel*'
reveal_type(get_list_or_404(MyModel)) # N: Revealed type is 'builtins.list[myapp.models.MyModel*]'
reveal_type(get_list_or_404(MyModel.objects)) # N: Revealed type is 'builtins.list[myapp.models.MyModel*]'
reveal_type(get_list_or_404(MyModel.objects.get_queryset())) # N: Revealed type is 'builtins.list[myapp.models.MyModel*]'
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyModel(models.Model):
pass
- case: get_user_model_returns_proper_class
disable_cache: true
main: |
from django.contrib.auth import get_user_model
UserModel = get_user_model()
reveal_type(UserModel.objects) # N: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyUser]'
custom_settings: |
INSTALLED_APPS = ('django.contrib.contenttypes', 'myapp')
AUTH_USER_MODEL = 'myapp.MyUser'
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class MyUser(models.Model):
pass
- case: check_render_function_arguments_annotations
main: |
from typing import Any
from typing_extensions import TypedDict
from django.shortcuts import render
from django.http.request import HttpRequest
TestContext = TypedDict("TestContext", {"user": Any})
test_context: TestContext = {"user": "test"}
reveal_type(test_context) # N: Revealed type is 'TypedDict('main.TestContext', {'user': Any})'
reveal_type(render(HttpRequest(), '', test_context)) # N: Revealed type is 'django.http.response.HttpResponse'
- case: check_redirect_return_annotation
main: |
from django.shortcuts import redirect
reveal_type(redirect(to = '', permanent = True)) # N: Revealed type is 'django.http.response.HttpResponsePermanentRedirect'
reveal_type(redirect(to = '', permanent = False)) # N: Revealed type is 'django.http.response.HttpResponseRedirect'
var = True
reveal_type(redirect(to = '', permanent = var)) # N: Revealed type is 'Union[django.http.response.HttpResponseRedirect, django.http.response.HttpResponsePermanentRedirect]'

View File

@@ -0,0 +1,20 @@
- case: method_decorator_class
main: |
from django.views.generic.base import View
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
@method_decorator(login_required, name='dispatch')
class TestView(View): ...
reveal_type(TestView()) # N: Revealed type is 'main.TestView'
- case: method_decorator_function
main: |
from django.views.generic.base import View
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.http.response import HttpResponse
from django.http.request import HttpRequest
class TestView(View):
@method_decorator(login_required)
def dispatch(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
return super().dispatch(request, *args, **kwargs)
reveal_type(dispatch) # N: Revealed type is 'def (self: main.TestView, request: django.http.request.HttpRequest, *args: Any, **kwargs: Any) -> django.http.response.HttpResponse'

View File

@@ -0,0 +1,18 @@
- case: cached_property_class_vs_instance_attributes
main: |
from django.utils.functional import cached_property
from typing import List
class Foo:
@cached_property
def attr(self) -> List[str]: ...
reveal_type(attr) # N: Revealed type is 'django.utils.functional.cached_property[builtins.list*[builtins.str]]'
reveal_type(attr.name) # N: Revealed type is 'builtins.str'
reveal_type(Foo.attr) # N: Revealed type is 'django.utils.functional.cached_property[builtins.list*[builtins.str]]'
reveal_type(Foo.attr.func) # N: Revealed type is 'def (*Any, **Any) -> builtins.list*[builtins.str]'
f = Foo()
reveal_type(f.attr) # N: Revealed type is 'builtins.list*[builtins.str]'
f.attr.name # E: "List[str]" has no attribute "name"