django-stubs
django-stubs copied to clipboard
WithAnnotations using a bound TypeVar causes MyPy to crash
Bug report
MyPy seems to fail with a recursion error when WithAnnotations
is used with a generic type variable as an argument. Here is a small example:
from typing import TypedDict, TypeVar
from django.db import models
from django_stubs_ext import WithAnnotations
class DoubleAnnotations(TypedDict):
double: int
_Content = TypeVar("_Content", bound="Record", covariant=True)
class RecordManager(models.Manager):
@staticmethod
def with_double(
queryset: models.QuerySet[_Content],
) -> models.QuerySet[WithAnnotations[_Content, DoubleAnnotations]]:
return queryset.annotate(double=models.F("value") * 2)
class Record(models.Model):
value = models.IntegerField()
objects = RecordManager()
The idea is that the manager provides a static method which annotates an existing queryset in some way (in my actual project, the annotation is way larger, hence it is refactored into a reusable method). But this should also work for querysets on subclasses of the model, hence the generic. Once a generic is involved, MyPy seems to crash:
Traceback
...
File "mypy/typeanal.py", line 887, in analyze_type
File "mypy/types.py", line 535, in accept
File "mypy/typeanal.py", line 164, in visit_unbound_type
File "mypy/typeanal.py", line 200, in visit_unbound_type_nonoptional
File "/nix/store/jxhqaq4crx0mhp1mgaqq9w1n393sbr8r-python3-3.9.6-env/lib/python3.9/site-packages/mypy_django_plugin/transformers/models.py", line 403, in handle_annotated_type
return ctx.api.analyze_type(ctx.type)
File "mypy/typeanal.py", line 887, in analyze_type
File "mypy/types.py", line 535, in accept
File "mypy/typeanal.py", line 164, in visit_unbound_type
File "mypy/typeanal.py", line 200, in visit_unbound_type_nonoptional
File "/nix/store/jxhqaq4crx0mhp1mgaqq9w1n393sbr8r-python3-3.9.6-env/lib/python3.9/site-packages/mypy_django_plugin/transformers/models.py", line 403, in handle_annotated_type
return ctx.api.analyze_type(ctx.type)
File "mypy/typeanal.py", line 887, in analyze_type
File "mypy/types.py", line 535, in accept
File "mypy/typeanal.py", line 164, in visit_unbound_type
File "mypy/typeanal.py", line 200, in visit_unbound_type_nonoptional
File "/nix/store/jxhqaq4crx0mhp1mgaqq9w1n393sbr8r-python3-3.9.6-env/lib/python3.9/site-packages/mypy_django_plugin/transformers/models.py", line 403, in handle_annotated_type
return ctx.api.analyze_type(ctx.type)
File "mypy/typeanal.py", line 887, in analyze_type
File "mypy/types.py", line 535, in accept
File "mypy/typeanal.py", line 164, in visit_unbound_type
File "mypy/typeanal.py", line 200, in visit_unbound_type_nonoptional
File "/nix/store/jxhqaq4crx0mhp1mgaqq9w1n393sbr8r-python3-3.9.6-env/lib/python3.9/site-packages/mypy_django_plugin/transformers/models.py", line 403, in handle_annotated_type
return ctx.api.analyze_type(ctx.type)
File "mypy/typeanal.py", line 887, in analyze_type
File "mypy/types.py", line 535, in accept
File "mypy/typeanal.py", line 164, in visit_unbound_type
File "mypy/typeanal.py", line 200, in visit_unbound_type_nonoptional
File "/nix/store/jxhqaq4crx0mhp1mgaqq9w1n393sbr8r-python3-3.9.6-env/lib/python3.9/site-packages/mypy_django_plugin/transformers/models.py", line 403, in handle_annotated_type
return ctx.api.analyze_type(ctx.type)
File "mypy/typeanal.py", line 887, in analyze_type
File "mypy/types.py", line 535, in accept
File "mypy/typeanal.py", line 164, in visit_unbound_type
File "mypy/typeanal.py", line 200, in visit_unbound_type_nonoptional
File "/nix/store/jxhqaq4crx0mhp1mgaqq9w1n393sbr8r-python3-3.9.6-env/lib/python3.9/site-packages/mypy_django_plugin/transformers/models.py", line 399, in handle_annotated_type
type_arg = ctx.api.analyze_type(args[0])
File "mypy/typeanal.py", line 887, in analyze_type
File "mypy/types.py", line 535, in accept
File "mypy/typeanal.py", line 164, in visit_unbound_type
File "mypy/typeanal.py", line 198, in visit_unbound_type_nonoptional
File "mypy/plugin.py", line 762, in get_type_analyze_hook
File "mypy/plugin.py", line 806, in _find_hook
File "mypy/plugin.py", line 762, in <lambda>
File "/nix/store/jxhqaq4crx0mhp1mgaqq9w1n393sbr8r-python3-3.9.6-env/lib/python3.9/site-packages/mypy_django_plugin/main.py", line 332, in get_type_analyze_hook
if fullname in (
RecursionError: maximum recursion depth exceeded in comparison
test.py:15: : note: use --pdb to drop into pdb
System information
- OS: NixOS
-
python
version: 3.9.6 -
django
version: 3.2.9 -
mypy
version: 0.920+dev -
django-stubs
version: 1.9.0 -
django-stubs-ext
version: 1.9.0
I am badly blocked by this issue (how WithAnnotations doesn't play nice with TypeVars and creating custom Managers/QuerySets etc). WithAnnotations is a time-losing honeypot at the moment
See https://github.com/typeddjango/django-stubs/issues/1046 and https://github.com/typeddjango/django-stubs/issues/1049