Skip to content

PEP 695 alias with WithAnnotations leaks its row type into unrelated QuerySet annotations #3424

Description

@milssky

Bug report

May be it related to #3423

A PEP 695 type alias containing QuerySet[WithAnnotations[...]] changes how unrelated QuerySet[Model] annotations are interpreted.

What's wrong

The annotated project type is incorrectly used as the row type of other querysets.

Reproduction

File structure:

repro/
├── __init__.py
├── settings.py
├── models.py
└── repository/
    ├── __init__.py
    ├── project.py
    └── user.py
mypy.ini

repro/settings.py:

SECRET_KEY = "repro"
INSTALLED_APPS = ["repro"]

repro/models.py:

from django.db import models


class Project(models.Model):
    name = models.CharField(max_length=100)


class User(models.Model):
    name = models.CharField(max_length=100)

repro/repository/project.py:

from typing import TypedDict

from django.db import models
from django_stubs_ext import WithAnnotations

from repro.models import Project


class ProjectAnnotations(TypedDict):
    occupied: int


type ProjectQuerySet = models.QuerySet[
    WithAnnotations[Project, ProjectAnnotations]
]


class ProjectRepository:
    def get_projects(self) -> ProjectQuerySet:
        return Project.objects.annotate(occupied=models.Count("id"))

repro/repository/user.py:

from django.db import models

from repro.models import User


class UserRepository:
    def get_users(self) -> models.QuerySet[User]:
        return User.objects.all()

repro/repository/__init__.py:

from repro.repository.project import ProjectRepository as ProjectRepository
from repro.repository.user import UserRepository as UserRepository

repro/__init__.py is empty.

mypy.ini:

[mypy]
plugins = mypy_django_plugin.main
strict = true

[mypy.plugins.django-stubs]
django_settings_module = repro.settings

Run:

mypy --no-incremental --config-file mypy.ini repro/repository/user.py

Actual behavior

repro/repository/user.py:8: error: Incompatible return value type
(got "QuerySet[User, User]",
expected "QuerySet[User, Project@AnnotatedWith[ProjectAnnotations]]")
[return-value]

The function is annotated as QuerySet[User], but mypy unexpectedly interprets its row type as Project@AnnotatedWith[ProjectAnnotations].

How is that should be

models.QuerySet[User] should be interpreted as:

QuerySet[User, User]

The ProjectQuerySet alias must not affect unrelated queryset annotations.

System information

  • OS: macos tahoe 26.5
  • python version: 3.13.11
  • django version: 6.0.6
  • mypy version: 2.1.0
  • django-stubs version:
  • django-stubs-ext version:

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions