diff --git a/mypy_django_plugin/django/context.py b/mypy_django_plugin/django/context.py index 09c6e96..ba76298 100644 --- a/mypy_django_plugin/django/context.py +++ b/mypy_django_plugin/django/context.py @@ -198,7 +198,12 @@ class DjangoContext: # it's generic, so cannot set specific model field_name = field.name gfk_info = helpers.lookup_class_typeinfo(api, field.__class__) - gfk_set_type = helpers.get_private_descriptor_type(gfk_info, "_pyi_private_set_type", is_nullable=True) + if gfk_info is None: + gfk_set_type = AnyType(TypeOfAny.unannotated) + else: + gfk_set_type = helpers.get_private_descriptor_type( + gfk_info, "_pyi_private_set_type", is_nullable=True + ) expected_types[field_name] = gfk_set_type return expected_types diff --git a/tests/typecheck/fields/test_generic_foreign_key.yml b/tests/typecheck/fields/test_generic_foreign_key.yml index d0979a8..b15690a 100644 --- a/tests/typecheck/fields/test_generic_foreign_key.yml +++ b/tests/typecheck/fields/test_generic_foreign_key.yml @@ -18,4 +18,27 @@ class User(models.Model): pass class Tag(models.Model): - content_object = fields.GenericForeignKey() \ No newline at end of file + content_object = fields.GenericForeignKey() +- case: generic_foreign_key_subclass_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() + # Simulate a GenericForeignKey subclass without type infos. + Tag.content_object.__class__ = type('MyGenericForeignKey', (fields.GenericForeignKey,), {})