diff --git a/mypy_django_plugin/transformers/managers.py b/mypy_django_plugin/transformers/managers.py index 2da8e50de..e4be536a2 100644 --- a/mypy_django_plugin/transformers/managers.py +++ b/mypy_django_plugin/transformers/managers.py @@ -10,6 +10,7 @@ MemberExpr, Node, OverloadedFuncDef, + PlaceholderNode, RefExpr, StrExpr, SymbolTableNode, @@ -317,6 +318,9 @@ def create_new_manager_class_from_from_queryset_method(ctx: DynamicClassDefConte new_manager_info = create_manager_info_from_from_queryset_call(semanal_api, ctx.call, ctx.name) if new_manager_info is None: if not ctx.api.final_iteration: + # XXX: hack for python/mypy#17402 + ph = PlaceholderNode(ctx.api.qualified_name(ctx.name), ctx.call, ctx.call.line, becomes_typeinfo=True) + ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(GDEF, ph)) ctx.api.defer() return diff --git a/tests/typecheck/managers/querysets/test_from_queryset.yml b/tests/typecheck/managers/querysets/test_from_queryset.yml index 8ce8eb6da..7ded784e3 100644 --- a/tests/typecheck/managers/querysets/test_from_queryset.yml +++ b/tests/typecheck/managers/querysets/test_from_queryset.yml @@ -822,6 +822,41 @@ self.ttl = ttl super().__init__(*a, **k) +- case: test_from_queryset_with_deferral + main: | + from myapp.models import Concrete + reveal_type(Concrete.objects.qs_meth()) # N: Revealed type is "builtins.int" + reveal_type(Concrete.objects.manager_meth()) # N: Revealed type is "builtins.str" + mypy_config: | + [mypy.plugins.django-stubs] + django_settings_module = myapp + files: + - path: myapp/__init__.py + - path: myapp/models.py + content: | + from typing import TypeVar, ClassVar + from typing_extensions import Self + from django.db import models + from django.db.models.manager import Manager + + M = TypeVar("M", bound=models.Model, covariant=True) + + # bogus forward-`metaclass=` to trigger second semanal pass similar to #2224 + class CustomQuerySet(models.QuerySet[M], metaclass=MCS): + def qs_meth(self) -> int: + return 1 + + _base = Manager.from_queryset(CustomQuerySet) + + class CustomBase(_base[M]): + def manager_meth(self) -> str: + return 'hi' + + class Concrete(models.Model): + objects: ClassVar[CustomBase[Self]] = CustomBase() + + class MCS(type): pass + - case: test_queryset_arg_as_unsupported_expressions main: | from typing import Union, Generic, TypeVar