mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-20 02:41:16 +08:00
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:
committed by
GitHub
parent
a3624dec36
commit
44151c485d
5
tests/plugins.ini
Normal file
5
tests/plugins.ini
Normal file
@@ -0,0 +1,5 @@
|
||||
[mypy]
|
||||
incremental = True
|
||||
strict_optional = True
|
||||
plugins =
|
||||
mypy_django_plugin.main
|
||||
72
tests/test_error_handling.py
Normal file
72
tests/test_error_handling.py
Normal 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"
|
||||
148
tests/typecheck/contrib/admin/test_options.yml
Normal file
148
tests/typecheck/contrib/admin/test_options.yml
Normal 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]")
|
||||
43
tests/typecheck/contrib/auth/test_decorators.yml
Normal file
43
tests/typecheck/contrib/auth/test_decorators.yml
Normal 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): ...
|
||||
26
tests/typecheck/db/models/test_init.yml
Normal file
26
tests/typecheck/db/models/test_init.yml
Normal 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")
|
||||
28
tests/typecheck/db/test_transaction.yml
Normal file
28
tests/typecheck/db/test_transaction.yml
Normal 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'
|
||||
|
||||
153
tests/typecheck/fields/test_base.yml
Normal file
153
tests/typecheck/fields/test_base.yml
Normal 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
|
||||
21
tests/typecheck/fields/test_generic_foreign_key.yml
Normal file
21
tests/typecheck/fields/test_generic_foreign_key.yml
Normal 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()
|
||||
70
tests/typecheck/fields/test_nullable.yml
Normal file
70
tests/typecheck/fields/test_nullable.yml
Normal 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)
|
||||
35
tests/typecheck/fields/test_postgres_fields.yml
Normal file
35
tests/typecheck/fields/test_postgres_fields.yml
Normal 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))
|
||||
674
tests/typecheck/fields/test_related.yml
Normal file
674
tests/typecheck/fields/test_related.yml
Normal 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')
|
||||
|
||||
47
tests/typecheck/managers/querysets/test_basic_methods.yml
Normal file
47
tests/typecheck/managers/querysets/test_basic_methods.yml
Normal 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
|
||||
256
tests/typecheck/managers/querysets/test_filter.yml
Normal file
256
tests/typecheck/managers/querysets/test_filter.yml
Normal 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()
|
||||
181
tests/typecheck/managers/querysets/test_from_queryset.yml
Normal file
181
tests/typecheck/managers/querysets/test_from_queryset.yml
Normal 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
|
||||
126
tests/typecheck/managers/querysets/test_values.yml
Normal file
126
tests/typecheck/managers/querysets/test_values.yml
Normal 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')
|
||||
243
tests/typecheck/managers/querysets/test_values_list.yml
Normal file
243
tests/typecheck/managers/querysets/test_values_list.yml
Normal 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')
|
||||
359
tests/typecheck/managers/test_managers.yml
Normal file
359
tests/typecheck/managers/test_managers.yml
Normal 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()
|
||||
|
||||
28
tests/typecheck/models/test_contrib_models.yml
Normal file
28
tests/typecheck/models/test_contrib_models.yml
Normal 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*'
|
||||
113
tests/typecheck/models/test_create.yml
Normal file
113
tests/typecheck/models/test_create.yml
Normal 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)
|
||||
56
tests/typecheck/models/test_extra_methods.yml
Normal file
56
tests/typecheck/models/test_extra_methods.yml
Normal 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)
|
||||
115
tests/typecheck/models/test_inheritance.yml
Normal file
115
tests/typecheck/models/test_inheritance.yml
Normal 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()
|
||||
257
tests/typecheck/models/test_init.yml
Normal file
257
tests/typecheck/models/test_init.yml
Normal 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
|
||||
58
tests/typecheck/models/test_meta_options.yml
Normal file
58
tests/typecheck/models/test_meta_options.yml
Normal 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=[])
|
||||
21
tests/typecheck/models/test_proxy_models.yml
Normal file
21
tests/typecheck/models/test_proxy_models.yml
Normal 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)
|
||||
14
tests/typecheck/models/test_state.yml
Normal file
14
tests/typecheck/models/test_state.yml
Normal 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
|
||||
12
tests/typecheck/test/test_testcase.yml
Normal file
12
tests/typecheck/test/test_testcase.yml
Normal 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'
|
||||
67
tests/typecheck/test_config.yml
Normal file
67
tests/typecheck/test_config.yml
Normal 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
|
||||
70
tests/typecheck/test_forms.yml
Normal file
70
tests/typecheck/test_forms.yml
Normal 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
|
||||
62
tests/typecheck/test_helpers.yml
Normal file
62
tests/typecheck/test_helpers.yml
Normal 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'
|
||||
442
tests/typecheck/test_import_all.yml
Normal file
442
tests/typecheck/test_import_all.yml
Normal 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
|
||||
54
tests/typecheck/test_request.yml
Normal file
54
tests/typecheck/test_request.yml
Normal 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')
|
||||
|
||||
50
tests/typecheck/test_settings.yml
Normal file
50
tests/typecheck/test_settings.yml
Normal 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()
|
||||
59
tests/typecheck/test_shortcuts.yml
Normal file
59
tests/typecheck/test_shortcuts.yml
Normal 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]'
|
||||
20
tests/typecheck/utils/test_decorators.yml
Normal file
20
tests/typecheck/utils/test_decorators.yml
Normal 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'
|
||||
18
tests/typecheck/utils/test_functional.yml
Normal file
18
tests/typecheck/utils/test_functional.yml
Normal 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"
|
||||
Reference in New Issue
Block a user