flix
flix

Reputation: 2033

How to typehint custom and overridden Managers in an Abstract Class using django-stubs?

we are trying to add typehints to our django (3.2) project. We are using django-stubs (1.12.0).

We have an AbstractBaseModel with a custom BaseManager that we use for almost every other model. In some cases we also extend the custom Manager.

Example:

class BaseManager(models.Manager):
    # ...

class AbstractBaseModel(models.Model):
    # ...
    objects = BaseManager()
    # ...

class MyManager(BaseManager):
    # ...

class MyModel(AbstractBaseModel):
    # ...
    objects = MyManager()
    # ...

When I run this through mypy (0.982), I get this error on the objects assignment of MyModel:

Incompatible types in assignment (expression has type "MyManager[MyModel]", 
base class "AbstractBaseModel" defined the type as 
"AbstractBaseModel_BaseManager2[AbstractBaseModel]")

How would I add typehints to this? Thank you!

Upvotes: 1

Views: 1371

Answers (1)

Daniil Fajnberg
Daniil Fajnberg

Reputation: 18663

As I said in my comment above, I could not reproduce that same error you described. It seems that in the django-stubs the BaseManager is defined as a covariant generic type over any Model (sub-)class.

So I would annotate the code you provided as follows:

from __future__ import annotations

from typing import TypeVar

from django.db import models


M = TypeVar("M", bound=models.Model, covariant=True)


class BaseManager(models.Manager[M]):
    pass


class AbstractBaseModel(models.Model):
    objects: BaseManager[AbstractBaseModel] = BaseManager()


class MyManager(BaseManager[M]):
    pass


class MyModel(AbstractBaseModel):
    objects: BaseManager[MyModel] = MyManager()

This passes mypy --strict without issues.

Versions used:

Python==3.10.7
Django==3.2
django-stubs==1.12.0
django-stubs-ext==0.5.0
mypy==0.982
mypy-extensions==0.4.3

Upvotes: 2

Related Questions