django-stubs icon indicating copy to clipboard operation
django-stubs copied to clipboard

var-annotated error with imported BaseModel, related to namespace module

Open blueyed opened this issue 3 years ago • 4 comments

As a followup to https://github.com/typeddjango/django-stubs/issues/68 I've noticed that it would not work with:

from django.db import models
from ...base.models import BaseModelMixin


# class BaseModelMixin(models.Model):
#     class Meta:
#         abstract = True


class TestModel(BaseModelMixin):
    foo = models.CharField(max_length=123)

error: Need type annotation for "foo" [var-annotated]

The imported model is the same as the commented one.

If not importing it, but defining it there (uncommenting it), it works:

from django.db import models
# from ...base.models import BaseModelMixin


class BaseModelMixin(models.Model):
    class Meta:
        abstract = True


class TestModel(BaseModelMixin):
    foo = models.CharField(max_length=123)

Note that it also fails when overwriting the import:

from django.db import models
# from ...base.models import BaseModelMixin


class BaseModelMixin(models.Model):
    class Meta:
        abstract = True


class TestModel(BaseModelMixin):
    foo = models.CharField(max_length=123)
…/models.py:5: error: Name "BaseModelMixin" already defined (possibly by an import)  [no-redef]                                                                                                    
…/models.py:11: error: Need type annotation for "foo"  [var-annotated]                                                                                                                             

I've not investigated much yet, but it appears to be caused by the models fullname not containing the first part of the (namespaced) module name: app.models.TestModel vs project.app.models.TestModel (via django_context.all_registered_model_class_fullnames)..!

This results in the is_model_subclass_info check only working if it is defined in the same file (via info.has_base check - shouldn't that work better maybe in general?): https://github.com/typeddjango/django-stubs/blob/cf6952c9df385a699dd63054b6753eb924b0c68c/mypy_django_plugin/lib/helpers.py#L304-L307

Note that the namespace ("project") is added/used via AppConfig:

class MyAppConfig(AppConfig):
    name = "project.app"

project/__init__.py does not exist, but creating it and/or changing ProductConfig.name to not include the namespace changes the behavior.

System information

  • OS: Arch Linux
  • python version: 3.9.5
  • django version: 4.0.dev20210602105309
  • mypy version: 0.910
  • django-stubs version: 1.8.0
  • django-stubs-ext version: 0.2.0

blueyed avatar Jul 02 '21 16:07 blueyed

@blueyed thanks for the report! Do you have a solution in mind? I would love to merge a fix for this.

sobolevn avatar Jul 02 '21 16:07 sobolevn

Any updates on this one?

nrbnlulu avatar Jan 16 '23 06:01 nrbnlulu

Any updates?

Leghart avatar Nov 17 '23 08:11 Leghart

Monkey-patching as following seems to be fixing the issue:

import mypy_django_plugin.lib.helpers
from mypy_django_plugin.lib.helpers import is_model_subclass_info as patch

PREFIX = "project."  # name of your namespace module


def is_model_subclass_info(info, django_context):
    if info.fullname.startswith(PREFIX):
        name = info.fullname[len(PREFIX) :]  # use removeprefix if py>=39
        if name in django_context.all_registered_model_class_fullnames:
            return True
    return patch(info, django_context)


mypy_django_plugin.lib.helpers.is_model_subclass_info = is_model_subclass_info

running mypy like so:

mypy -p project

@sobolevn I'm guessing we need to prefix namespace modules in all_registered_model_class_fullnames property? I'm not sure if how would we fetch that information in that context.

realsuayip avatar Feb 07 '24 11:02 realsuayip