Skip to content

Commit 07704b1

Browse files
committed
Remove QuerySet alias hacks via PEP 696 TypeVar defaults
The `QuerySet` class was previously named `_QuerySet` and had three aliases: `QuerySet`, `QuerySetAny` and `ValuesQuerySet`. These hacks were mainly needed to for the ergonomic single-parameter `QuerySet[Model]`, which expanded into `_QuerySet[Model, Model]` But now that mypy 1.10 implements PEP 696 to a fuller extent (Pyright also supports it), the 2nd type parameter can be a simple TypeVar that defaults to 1st type parameter.
1 parent ea8e425 commit 07704b1

File tree

14 files changed

+92
-93
lines changed

14 files changed

+92
-93
lines changed

django-stubs/db/models/manager.pyi

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ from django.db.models.expressions import Combinable, OrderBy
77
from django.db.models.query import QuerySet, RawQuerySet
88
from typing_extensions import Self
99

10-
from django_stubs_ext import ValuesQuerySet
11-
1210
_T = TypeVar("_T", bound=Model, covariant=True)
1311

1412
class BaseManager(Generic[_T]):
@@ -107,15 +105,13 @@ class BaseManager(Generic[_T]):
107105
using: str | None = ...,
108106
) -> RawQuerySet: ...
109107
# The type of values may be overridden to be more specific in the mypy plugin, depending on the fields param
110-
def values(self, *fields: str | Combinable, **expressions: Any) -> ValuesQuerySet[_T, dict[str, Any]]: ...
108+
def values(self, *fields: str | Combinable, **expressions: Any) -> QuerySet[_T, dict[str, Any]]: ...
111109
# The type of values_list may be overridden to be more specific in the mypy plugin, depending on the fields param
112-
def values_list(
113-
self, *fields: str | Combinable, flat: bool = ..., named: bool = ...
114-
) -> ValuesQuerySet[_T, Any]: ...
115-
def dates(self, field_name: str, kind: str, order: str = ...) -> ValuesQuerySet[_T, datetime.date]: ...
110+
def values_list(self, *fields: str | Combinable, flat: bool = ..., named: bool = ...) -> QuerySet[_T, Any]: ...
111+
def dates(self, field_name: str, kind: str, order: str = ...) -> QuerySet[_T, datetime.date]: ...
116112
def datetimes(
117113
self, field_name: str, kind: str, order: str = ..., tzinfo: datetime.tzinfo | None = ...
118-
) -> ValuesQuerySet[_T, datetime.datetime]: ...
114+
) -> QuerySet[_T, datetime.datetime]: ...
119115
def none(self) -> QuerySet[_T]: ...
120116
def all(self) -> QuerySet[_T]: ...
121117
def filter(self, *args: Any, **kwargs: Any) -> QuerySet[_T]: ...

django-stubs/db/models/query.pyi

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
11
import datetime
22
from collections.abc import AsyncIterator, Collection, Iterable, Iterator, MutableMapping, Sequence, Sized
3-
from typing import Any, Generic, NamedTuple, TypeVar, overload
3+
from typing import Any, Generic, NamedTuple, overload
44

55
from django.db.backends.utils import _ExecuteQuery
66
from django.db.models import Manager
77
from django.db.models.base import Model
88
from django.db.models.expressions import Combinable, OrderBy
99
from django.db.models.sql.query import Query, RawQuery
1010
from django.utils.functional import cached_property
11-
from typing_extensions import Self, TypeAlias
11+
from typing_extensions import Self, TypeAlias, TypeVar
1212

13-
_T = TypeVar("_T", bound=Model, covariant=True)
14-
_Row = TypeVar("_Row", covariant=True)
13+
_T = TypeVar("_T", covariant=True)
14+
_Model = TypeVar("_Model", bound=Model, covariant=True)
15+
_Row = TypeVar("_Row", covariant=True, default=_Model) # ONLY use together with _Model
1516
_QS = TypeVar("_QS", bound=_QuerySet)
1617
_TupleT = TypeVar("_TupleT", bound=tuple[Any, ...], covariant=True)
1718

1819
MAX_GET_RESULTS: int
1920
REPR_OUTPUT_SIZE: int
2021

21-
class BaseIterable(Generic[_Row]):
22+
class BaseIterable(Generic[_T]):
2223
queryset: QuerySet[Model]
2324
chunked_fetch: bool
2425
chunk_size: int
2526
def __init__(self, queryset: QuerySet[Model], chunked_fetch: bool = ..., chunk_size: int = ...) -> None: ...
26-
def __aiter__(self) -> AsyncIterator[_Row]: ...
27+
def __aiter__(self) -> AsyncIterator[_T]: ...
2728

28-
class ModelIterable(Generic[_T], BaseIterable[_T]):
29-
def __iter__(self) -> Iterator[_T]: ...
29+
class ModelIterable(Generic[_Model], BaseIterable[_Model]):
30+
def __iter__(self) -> Iterator[_Model]: ...
3031

3132
class RawModelIterable(BaseIterable[dict[str, Any]]):
3233
def __iter__(self) -> Iterator[dict[str, Any]]: ...
@@ -40,11 +41,11 @@ class ValuesListIterable(BaseIterable[_TupleT]):
4041
class NamedValuesListIterable(ValuesListIterable[NamedTuple]):
4142
def __iter__(self) -> Iterator[NamedTuple]: ...
4243

43-
class FlatValuesListIterable(BaseIterable[_Row]):
44-
def __iter__(self) -> Iterator[_Row]: ...
44+
class FlatValuesListIterable(BaseIterable[_T]):
45+
def __iter__(self) -> Iterator[_T]: ...
4546

46-
class _QuerySet(Generic[_T, _Row], Iterable[_Row], Sized):
47-
model: type[_T]
47+
class QuerySet(Generic[_Model, _Row], Iterable[_Row], Sized):
48+
model: type[_Model]
4849
query: Query
4950
_iterable_class: type[BaseIterable]
5051
_result_cache: list[_Row] | None
@@ -56,14 +57,14 @@ class _QuerySet(Generic[_T, _Row], Iterable[_Row], Sized):
5657
hints: dict[str, Model] | None = ...,
5758
) -> None: ...
5859
@classmethod
59-
def as_manager(cls) -> Manager[_T]: ...
60+
def as_manager(cls) -> Manager[_Model]: ...
6061
def __len__(self) -> int: ...
6162
def __bool__(self) -> bool: ...
62-
def __class_getitem__(cls: type[_QS], item: type[_T]) -> type[_QS]: ...
63+
def __class_getitem__(cls: type[_QS], item: type[_Model]) -> type[_QS]: ...
6364
def __getstate__(self) -> dict[str, Any]: ...
6465
# Technically, the other QuerySet must be of the same type _T, but _T is covariant
65-
def __and__(self, other: _QuerySet[_T, _Row]) -> Self: ...
66-
def __or__(self, other: _QuerySet[_T, _Row]) -> Self: ...
66+
def __and__(self, other: QuerySet[_Model, _Row]) -> Self: ...
67+
def __or__(self, other: QuerySet[_Model, _Row]) -> Self: ...
6768
# IMPORTANT: When updating any of the following methods' signatures, please ALSO modify
6869
# the corresponding method in BaseManager.
6970
def iterator(self, chunk_size: int | None = ...) -> Iterator[_Row]: ...
@@ -72,44 +73,46 @@ class _QuerySet(Generic[_T, _Row], Iterable[_Row], Sized):
7273
async def aaggregate(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ...
7374
def get(self, *args: Any, **kwargs: Any) -> _Row: ...
7475
async def aget(self, *args: Any, **kwargs: Any) -> _Row: ...
75-
def create(self, **kwargs: Any) -> _T: ...
76-
async def acreate(self, **kwargs: Any) -> _T: ...
76+
def create(self, **kwargs: Any) -> _Model: ...
77+
async def acreate(self, **kwargs: Any) -> _Model: ...
7778
def bulk_create(
7879
self,
79-
objs: Iterable[_T],
80+
objs: Iterable[_Model],
8081
batch_size: int | None = ...,
8182
ignore_conflicts: bool = ...,
8283
update_conflicts: bool = ...,
8384
update_fields: Collection[str] | None = ...,
8485
unique_fields: Collection[str] | None = ...,
85-
) -> list[_T]: ...
86+
) -> list[_Model]: ...
8687
async def abulk_create(
8788
self,
88-
objs: Iterable[_T],
89+
objs: Iterable[_Model],
8990
batch_size: int | None = ...,
9091
ignore_conflicts: bool = ...,
9192
update_conflicts: bool = ...,
9293
update_fields: Collection[str] | None = ...,
9394
unique_fields: Collection[str] | None = ...,
94-
) -> list[_T]: ...
95-
def bulk_update(self, objs: Iterable[_T], fields: Iterable[str], batch_size: int | None = ...) -> int: ...
96-
async def abulk_update(self, objs: Iterable[_T], fields: Iterable[str], batch_size: int | None = ...) -> int: ...
97-
def get_or_create(self, defaults: MutableMapping[str, Any] | None = ..., **kwargs: Any) -> tuple[_T, bool]: ...
95+
) -> list[_Model]: ...
96+
def bulk_update(self, objs: Iterable[_Model], fields: Iterable[str], batch_size: int | None = ...) -> int: ...
97+
async def abulk_update(
98+
self, objs: Iterable[_Model], fields: Iterable[str], batch_size: int | None = ...
99+
) -> int: ...
100+
def get_or_create(self, defaults: MutableMapping[str, Any] | None = ..., **kwargs: Any) -> tuple[_Model, bool]: ...
98101
async def aget_or_create(
99102
self, defaults: MutableMapping[str, Any] | None = ..., **kwargs: Any
100-
) -> tuple[_T, bool]: ...
103+
) -> tuple[_Model, bool]: ...
101104
def update_or_create(
102105
self,
103106
defaults: MutableMapping[str, Any] | None = ...,
104107
create_defaults: MutableMapping[str, Any] | None = ...,
105108
**kwargs: Any,
106-
) -> tuple[_T, bool]: ...
109+
) -> tuple[_Model, bool]: ...
107110
async def aupdate_or_create(
108111
self,
109112
defaults: MutableMapping[str, Any] | None = ...,
110113
create_defaults: MutableMapping[str, Any] | None = ...,
111114
**kwargs: Any,
112-
) -> tuple[_T, bool]: ...
115+
) -> tuple[_Model, bool]: ...
113116
def earliest(self, *fields: str | OrderBy) -> _Row: ...
114117
async def aearliest(self, *fields: str | OrderBy) -> _Row: ...
115118
def latest(self, *fields: str | OrderBy) -> _Row: ...
@@ -118,8 +121,8 @@ class _QuerySet(Generic[_T, _Row], Iterable[_Row], Sized):
118121
async def afirst(self) -> _Row | None: ...
119122
def last(self) -> _Row | None: ...
120123
async def alast(self) -> _Row | None: ...
121-
def in_bulk(self, id_list: Iterable[Any] | None = ..., *, field_name: str = ...) -> dict[Any, _T]: ...
122-
async def ain_bulk(self, id_list: Iterable[Any] | None = ..., *, field_name: str = ...) -> dict[Any, _T]: ...
124+
def in_bulk(self, id_list: Iterable[Any] | None = ..., *, field_name: str = ...) -> dict[Any, _Model]: ...
125+
async def ain_bulk(self, id_list: Iterable[Any] | None = ..., *, field_name: str = ...) -> dict[Any, _Model]: ...
123126
def delete(self) -> tuple[int, dict[str, int]]: ...
124127
async def adelete(self) -> tuple[int, dict[str, int]]: ...
125128
def update(self, **kwargs: Any) -> int: ...
@@ -138,13 +141,13 @@ class _QuerySet(Generic[_T, _Row], Iterable[_Row], Sized):
138141
using: str | None = ...,
139142
) -> RawQuerySet: ...
140143
# The type of values may be overridden to be more specific in the mypy plugin, depending on the fields param
141-
def values(self, *fields: str | Combinable, **expressions: Any) -> _QuerySet[_T, dict[str, Any]]: ...
144+
def values(self, *fields: str | Combinable, **expressions: Any) -> QuerySet[_Model, dict[str, Any]]: ...
142145
# The type of values_list may be overridden to be more specific in the mypy plugin, depending on the fields param
143-
def values_list(self, *fields: str | Combinable, flat: bool = ..., named: bool = ...) -> _QuerySet[_T, Any]: ...
144-
def dates(self, field_name: str, kind: str, order: str = ...) -> _QuerySet[_T, datetime.date]: ...
146+
def values_list(self, *fields: str | Combinable, flat: bool = ..., named: bool = ...) -> QuerySet[_Model, Any]: ...
147+
def dates(self, field_name: str, kind: str, order: str = ...) -> QuerySet[_Model, datetime.date]: ...
145148
def datetimes(
146149
self, field_name: str, kind: str, order: str = ..., tzinfo: datetime.tzinfo | None = ...
147-
) -> _QuerySet[_T, datetime.datetime]: ...
150+
) -> QuerySet[_Model, datetime.datetime]: ...
148151
def none(self) -> Self: ...
149152
def all(self) -> Self: ...
150153
def filter(self, *args: Any, **kwargs: Any) -> Self: ...
@@ -173,7 +176,7 @@ class _QuerySet(Generic[_T, _Row], Iterable[_Row], Sized):
173176
tables: Sequence[str] | None = ...,
174177
order_by: Sequence[str] | None = ...,
175178
select_params: Sequence[Any] | None = ...,
176-
) -> _QuerySet[Any, Any]: ...
179+
) -> QuerySet[Any, Any]: ...
177180
def reverse(self) -> Self: ...
178181
def defer(self, *fields: Any) -> Self: ...
179182
def only(self, *fields: Any) -> Self: ...
@@ -192,7 +195,7 @@ class _QuerySet(Generic[_T, _Row], Iterable[_Row], Sized):
192195
def __getitem__(self, s: slice) -> Self: ...
193196
def __reversed__(self) -> Iterator[_Row]: ...
194197

195-
class RawQuerySet(Iterable[_T], Sized):
198+
class RawQuerySet(Iterable[_Model], Sized):
196199
query: RawQuery
197200
def __init__(
198201
self,
@@ -205,28 +208,28 @@ class RawQuerySet(Iterable[_T], Sized):
205208
hints: dict[str, Model] | None = ...,
206209
) -> None: ...
207210
def __len__(self) -> int: ...
208-
def __iter__(self) -> Iterator[_T]: ...
211+
def __iter__(self) -> Iterator[_Model]: ...
209212
def __bool__(self) -> bool: ...
210213
@overload
211-
def __getitem__(self, k: int) -> _T: ...
214+
def __getitem__(self, k: int) -> _Model: ...
212215
@overload
213216
def __getitem__(self, k: str) -> Any: ...
214217
@overload
215-
def __getitem__(self, k: slice) -> RawQuerySet[_T]: ...
218+
def __getitem__(self, k: slice) -> RawQuerySet[_Model]: ...
216219
@cached_property
217220
def columns(self) -> list[str]: ...
218221
@property
219222
def db(self) -> str: ...
220-
def iterator(self) -> Iterator[_T]: ...
223+
def iterator(self) -> Iterator[_Model]: ...
221224
@cached_property
222225
def model_fields(self) -> dict[str, str]: ...
223-
def prefetch_related(self, *lookups: Any) -> RawQuerySet[_T]: ...
226+
def prefetch_related(self, *lookups: Any) -> RawQuerySet[_Model]: ...
224227
def resolve_model_init_order(self) -> tuple[list[str], list[int], list[tuple[str, int]]]: ...
225-
def using(self, alias: str | None) -> RawQuerySet[_T]: ...
226-
227-
_QuerySetAny: TypeAlias = _QuerySet # noqa: PYI047
228+
def using(self, alias: str | None) -> RawQuerySet[_Model]: ...
228229

229-
QuerySet: TypeAlias = _QuerySet[_T, _T]
230+
# Obsolete aliases of QuerySet, for compatibility only.
231+
_QuerySet: TypeAlias = QuerySet[_T, _Row]
232+
_QuerySetAny: TypeAlias = QuerySet # noqa: PYI047
230233

231234
class Prefetch:
232235
prefetch_through: str
@@ -240,8 +243,8 @@ class Prefetch:
240243
def get_current_to_attr(self, level: int) -> tuple[str, str]: ...
241244
def get_current_queryset(self, level: int) -> QuerySet | None: ...
242245

243-
def prefetch_related_objects(model_instances: Iterable[_T], *related_lookups: str | Prefetch) -> None: ...
244-
async def aprefetch_related_objects(model_instances: Iterable[_T], *related_lookups: str | Prefetch) -> None: ...
246+
def prefetch_related_objects(model_instances: Iterable[_Model], *related_lookups: str | Prefetch) -> None: ...
247+
async def aprefetch_related_objects(model_instances: Iterable[_Model], *related_lookups: str | Prefetch) -> None: ...
245248
def get_prefetcher(instance: Model, through_attr: str, to_attr: str) -> tuple[Any, Any, bool, bool]: ...
246249

247250
class InstanceCheckMeta(type): ...

ext/django_stubs_ext/aliases.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from django.utils.functional import _StrPromise as StrPromise
77

88
QuerySetAny = _QuerySetAny
9-
ValuesQuerySet = _QuerySet[_T, _Row]
9+
ValuesQuerySet = _QuerySet[_T, _Row] # TODO think about this!
1010
else:
1111
from django.db.models.query import QuerySet
1212
from django.utils.functional import Promise as StrPromise

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def find_stub_files(name: str) -> List[str]:
2626
"django-stubs-ext>=5.0.0",
2727
"tomli; python_version < '3.11'",
2828
# Types:
29-
"typing-extensions",
29+
"typing-extensions>=4.11.0",
3030
"types-PyYAML",
3131
]
3232

tests/typecheck/contrib/admin/test_decorators.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
def method_action_invalid_fancy(self, request: HttpRequest, queryset: int) -> None: ...
109109
110110
def method(self) -> None:
111-
reveal_type(self.method_action_bare) # N: Revealed type is "def (django.http.request.HttpRequest, django.db.models.query._QuerySet[main.MyModel, main.MyModel])"
112-
reveal_type(self.method_action_fancy) # N: Revealed type is "def (django.http.request.HttpRequest, django.db.models.query._QuerySet[main.MyModel, main.MyModel])"
113-
reveal_type(self.method_action_http_response) # N: Revealed type is "def (django.http.request.HttpRequest, django.db.models.query._QuerySet[main.MyModel, main.MyModel]) -> django.http.response.HttpResponse"
114-
reveal_type(self.method_action_file_response) # N: Revealed type is "def (django.http.request.HttpRequest, django.db.models.query._QuerySet[main.MyModel, main.MyModel]) -> django.http.response.FileResponse"
111+
reveal_type(self.method_action_bare) # N: Revealed type is "def (django.http.request.HttpRequest, django.db.models.query.QuerySet[main.MyModel, main.MyModel])"
112+
reveal_type(self.method_action_fancy) # N: Revealed type is "def (django.http.request.HttpRequest, django.db.models.query.QuerySet[main.MyModel, main.MyModel])"
113+
reveal_type(self.method_action_http_response) # N: Revealed type is "def (django.http.request.HttpRequest, django.db.models.query.QuerySet[main.MyModel, main.MyModel]) -> django.http.response.HttpResponse"
114+
reveal_type(self.method_action_file_response) # N: Revealed type is "def (django.http.request.HttpRequest, django.db.models.query.QuerySet[main.MyModel, main.MyModel]) -> django.http.response.FileResponse"

tests/typecheck/fields/test_related.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,7 @@
10581058
out: |
10591059
main:2: note: Revealed type is "Type[django.core.exceptions.ObjectDoesNotExist]"
10601060
main:3: note: Revealed type is "django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor[myapp.models.Other, myapp.models.MyModel]"
1061-
main:4: note: Revealed type is "django.db.models.query._QuerySet[myapp.models.MyModel, myapp.models.MyModel]"
1061+
main:4: note: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel, myapp.models.MyModel]"
10621062
main:5: note: Revealed type is "Type[django.core.exceptions.ObjectDoesNotExist]"
10631063
main:6: note: Revealed type is "Type[django.core.exceptions.ObjectDoesNotExist]"
10641064
main:9: note: Revealed type is "myapp.models.MyModel"

tests/typecheck/managers/querysets/test_annotate.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
from django.db.models.expressions import F
120120
121121
qs = User.objects.annotate(foo=F('id'))
122-
reveal_type(qs) # N: Revealed type is "django.db.models.query._QuerySet[django_stubs_ext.WithAnnotations[myapp__models__User, TypedDict({'foo': Any})], django_stubs_ext.WithAnnotations[myapp__models__User, TypedDict({'foo': Any})]]"
122+
reveal_type(qs) # N: Revealed type is "django.db.models.query.QuerySet[django_stubs_ext.WithAnnotations[myapp__models__User, TypedDict({'foo': Any})], django_stubs_ext.WithAnnotations[myapp__models__User, TypedDict({'foo': Any})]]"
123123
124124
annotated = qs.get()
125125
reveal_type(annotated) # N: Revealed type is "django_stubs_ext.WithAnnotations[myapp__models__User, TypedDict({'foo': Any})]"
@@ -144,7 +144,7 @@
144144
from django.db.models import Count
145145
146146
qs = User.objects.annotate(Count('id'))
147-
reveal_type(qs) # N: Revealed type is "django.db.models.query._QuerySet[django_stubs_ext.WithAnnotations[myapp__models__User], django_stubs_ext.WithAnnotations[myapp__models__User]]"
147+
reveal_type(qs) # N: Revealed type is "django.db.models.query.QuerySet[django_stubs_ext.WithAnnotations[myapp__models__User], django_stubs_ext.WithAnnotations[myapp__models__User]]"
148148
149149
installed_apps:
150150
- myapp
@@ -308,19 +308,19 @@
308308
# It's possible to provide more precise types than than this, but without inspecting the
309309
# arguments to .annotate, these are the best types we can infer.
310310
qs1 = Blog.objects.values('text').annotate(foo=F('id'))
311-
reveal_type(qs1) # N: Revealed type is "django.db.models.query._QuerySet[django_stubs_ext.WithAnnotations[myapp__models__Blog, TypedDict({'foo': Any})], builtins.dict[builtins.str, Any]]"
311+
reveal_type(qs1) # N: Revealed type is "django.db.models.query.QuerySet[django_stubs_ext.WithAnnotations[myapp__models__Blog, TypedDict({'foo': Any})], builtins.dict[builtins.str, Any]]"
312312
qs2 = Blog.objects.values_list('text').annotate(foo=F('id'))
313-
reveal_type(qs2) # N: Revealed type is "django.db.models.query._QuerySet[django_stubs_ext.WithAnnotations[myapp__models__Blog, TypedDict({'foo': Any})], builtins.tuple[Any, ...]]"
313+
reveal_type(qs2) # N: Revealed type is "django.db.models.query.QuerySet[django_stubs_ext.WithAnnotations[myapp__models__Blog, TypedDict({'foo': Any})], builtins.tuple[Any, ...]]"
314314
qs3 = Blog.objects.values_list('text', named=True).annotate(foo=F('id'))
315315
# TODO: Would be nice to infer a NamedTuple which contains the field 'text' (str) + any number of other fields.
316316
# The reason it would have to appear to have any other fields is that annotate could potentially be called with
317317
# arbitrary parameters such that we wouldn't know how many extra fields there might be.
318318
# But it's not trivial to make such a NamedTuple, partly because since it is also an ordinary tuple, it would
319319
# have to have an arbitrary length, but still have certain fields at certain indices with specific types.
320320
# For now, Any :)
321-
reveal_type(qs3) # N: Revealed type is "django.db.models.query._QuerySet[django_stubs_ext.WithAnnotations[myapp__models__Blog, TypedDict({'foo': Any})], Any]"
321+
reveal_type(qs3) # N: Revealed type is "django.db.models.query.QuerySet[django_stubs_ext.WithAnnotations[myapp__models__Blog, TypedDict({'foo': Any})], Any]"
322322
qs4 = Blog.objects.values_list('text', flat=True).annotate(foo=F('id'))
323-
reveal_type(qs4) # N: Revealed type is "django.db.models.query._QuerySet[django_stubs_ext.WithAnnotations[myapp__models__Blog, TypedDict({'foo': Any})], builtins.str]"
323+
reveal_type(qs4) # N: Revealed type is "django.db.models.query.QuerySet[django_stubs_ext.WithAnnotations[myapp__models__Blog, TypedDict({'foo': Any})], builtins.str]"
324324
325325
326326
before_values_no_params = Blog.objects.values().annotate(foo=F('id')).get()

0 commit comments

Comments
 (0)