Jasper
Jasper

Reputation: 2231

Python / Django - Mypy: expression has type "Type[ModelInstance]", variable has type "ModelInstance"

I'm working on a Django app that provides a GraphQL api for the frontend. I'm using mypy for typechecking and when running mypy I'm encountering errors that I do not understand

When running I get the following errors:

api/schema.py:50: error: Incompatible types in assignment (expression has type "Type[Academy]", variable has type "Academy")
api/schema.py:57: error: Incompatible types in assignment (expression has type "Type[School]", variable has type "School")
api/schema.py:64: error: Incompatible types in assignment (expression has type "Type[AcademyGroup]", variable has type "AcademyGroup")

This is the code that mypy is checking

class AcademyType(DjangoObjectType):
    class Meta:
        model: Academy = Academy
        filter_fields: List[str] = ['name', 'domain', 'slug']
        interfaces: Tuple = (relay.Node,)


class SchoolType(DjangoObjectType):
    class Meta:
        model: School = School
        filter_fields: List[str] = ['name', 'academy']
        interfaces: Tuple = (relay.Node,)


class AcademyGroupType(DjangoObjectType):
    class Meta:
        model: AcademyGroup = AcademyGroup
        filter_fields: List[str] = ['name', 'academy']
        interfaces: Tuple = (relay.Node,)

So the lines that keep failing are variants on model: AcademyGroup = AcademyGroup, but that is just a 'Django model as type' definition that is happening all over my code (and does not seem to be generating errors)

As such I'm not really sure what I am doing wrong here, so any help would be greatly appreciated.

Upvotes: 1

Views: 822

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477240

The type of your model attributes is not the class itself, but a Type. Indeed, if you say model = Academy, then the type of model is type(model) == type(Academy) == Type, indeed, Academy is not an Academy object, it is a reference to the class, the type of such class is a (subclass) of Type. You can furthermore use Type[…] [python-doc] to specify the (base-)class of the type, so Type[C] means it is a type that is C, or a subclass of C:

You thus should annotate it as:

from typing import Type

class AcademyType(DjangoObjectType):
    class Meta:
        model: Type[Academy] = Academy
        filter_fields: List[str] = ['name', 'domain', 'slug']
        interfaces: Tuple = (relay.Node,)


class SchoolType(DjangoObjectType):
    class Meta:
        model: Type[School] = School
        filter_fields: List[str] = ['name', 'academy']
        interfaces: Tuple = (relay.Node,)


class AcademyGroupType(DjangoObjectType):
    class Meta:
        model: Type[AcademyGroup] = AcademyGroup
        filter_fields: List[str] = ['name', 'academy']
        interfaces: Tuple = (relay.Node,)

Upvotes: 2

Related Questions