From 3fb3bbcf197056a2ae195b97f990c0bd66b3b8c9 Mon Sep 17 00:00:00 2001 From: Maxim Kurnikov Date: Thu, 7 Feb 2019 01:01:05 +0300 Subject: [PATCH] fix values_list --- django-stubs/db/models/base.pyi | 4 +-- django-stubs/db/models/fields/__init__.pyi | 4 +++ django-stubs/db/models/query.pyi | 31 +++++++++++++++++++--- django-stubs/utils/datastructures.pyi | 1 + scripts/typecheck_tests.py | 6 +++-- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/django-stubs/db/models/base.pyi b/django-stubs/db/models/base.pyi index 98b17d1..a581220 100644 --- a/django-stubs/db/models/base.pyi +++ b/django-stubs/db/models/base.pyi @@ -7,8 +7,8 @@ class ModelBase(type): ... _Self = TypeVar("_Self", bound="Model") class Model(metaclass=ModelBase): - class DoesNotExist(Exception): - pass + class DoesNotExist(Exception): ... + class Meta: ... _meta: Any pk: Any = ... objects: Manager[Model] diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index cf70a1f..71a71fd 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -231,6 +231,7 @@ class DateField(DateTimeCheckMixin, Field): validators: Iterable[_ValidatorCallable] = ..., error_messages: Optional[_ErrorMessagesToOverride] = ..., ): ... + def __set__(self, instance, value: Any) -> None: ... def __get__(self, instance, owner) -> date: ... class TimeField(DateTimeCheckMixin, Field): @@ -256,12 +257,15 @@ class TimeField(DateTimeCheckMixin, Field): validators: Iterable[_ValidatorCallable] = ..., error_messages: Optional[_ErrorMessagesToOverride] = ..., ): ... + def __set__(self, instance, value: Any) -> None: ... def __get__(self, instance, owner) -> time: ... class DateTimeField(DateField): + def __set__(self, instance, value: Any) -> None: ... def __get__(self, instance, owner) -> datetime: ... class UUIDField(Field): + def __set__(self, instance, value: Any) -> None: ... def __get__(self, instance, owner) -> uuid.UUID: ... class FilePathField(Field): diff --git a/django-stubs/db/models/query.pyi b/django-stubs/db/models/query.pyi index 92f7a8e..88c4e28 100644 --- a/django-stubs/db/models/query.pyi +++ b/django-stubs/db/models/query.pyi @@ -18,11 +18,32 @@ from typing import ( from django.db.models.base import Model from django.db.models.expressions import Combinable as Combinable, F as F from django.db.models.sql.query import Query, RawQuery +from typing_extensions import Literal from django.db import models from django.db.models import Manager from django.db.models.query_utils import Q as Q +_Row = TypeVar("_Row", covariant=True) + +class BaseIterable(Sequence[_Row]): + def __init__(self, queryset: QuerySet, chunked_fetch: bool = ..., chunk_size: int = ...): ... + def __iter__(self) -> Iterator[_Row]: ... + def __contains__(self, x: object) -> bool: ... + def __len__(self) -> int: ... + @overload + def __getitem__(self, i: int) -> _Row: ... + @overload + def __getitem__(self, s: slice) -> Sequence[_Row]: ... + +class ModelIterable(BaseIterable[Model]): ... +class ValuesIterable(BaseIterable[Dict[str, Any]]): ... +class ValuesListIterable(BaseIterable[Tuple]): ... +class NamedValuesListIterable(ValuesListIterable): ... + +class FlatValuesListIterable(BaseIterable): + def __iter__(self) -> Iterator[Any]: ... + _T = TypeVar("_T", bound=models.Model, covariant=True) class QuerySet(Iterable[_T], Sized): @@ -75,7 +96,12 @@ class QuerySet(Iterable[_T], Sized): self, raw_query: str, params: Any = ..., translations: Optional[Dict[str, str]] = ..., using: None = ... ) -> RawQuerySet: ... def values(self, *fields: Union[str, Combinable], **expressions: Any) -> QuerySet: ... - def values_list(self, *fields: Union[str, Combinable], flat: bool = ..., named: bool = ...) -> QuerySet: ... + @overload + def values_list(self, *fields: Union[str, Combinable], named: Literal[True]) -> NamedValuesListIterable: ... + @overload + def values_list(self, *fields: Union[str, Combinable], flat: Literal[True]) -> FlatValuesListIterable: ... + @overload + def values_list(self, *fields: Union[str, Combinable]) -> ValuesListIterable: ... def dates(self, field_name: str, kind: str, order: str = ...) -> QuerySet: ... def datetimes(self, field_name: str, kind: str, order: str = ..., tzinfo: None = ...) -> QuerySet: ... def none(self) -> QuerySet[_T]: ... @@ -157,8 +183,5 @@ class Prefetch(object): def prefetch_related_objects(model_instances: Iterable[_T], *related_lookups: Union[str, Prefetch]) -> None: ... def get_prefetcher(instance: Model, through_attr: str, to_attr: str) -> Tuple[Any, Any, bool, bool]: ... -class ModelIterable(Iterable[_T]): - def __iter__(self) -> Iterator[_T]: ... - class InstanceCheckMeta(type): ... class EmptyQuerySet(metaclass=InstanceCheckMeta): ... diff --git a/django-stubs/utils/datastructures.pyi b/django-stubs/utils/datastructures.pyi index 3f4ef50..384fb8b 100644 --- a/django-stubs/utils/datastructures.pyi +++ b/django-stubs/utils/datastructures.pyi @@ -40,6 +40,7 @@ class MultiValueDict(MutableMapping[_K, _V]): def appendlist(self, key: _K, value: _V) -> None: ... def lists(self) -> Iterable[Tuple[_K, List[_V]]]: ... def dict(self) -> Dict[_K, _Val]: ... + def copy(self) -> MultiValueDict[_K, _V]: ... # These overrides are needed to convince mypy that this isn't an abstract class def __delitem__(self, item: _K) -> None: ... def __getitem__(self, item: _K) -> _Val: ... # type: ignore diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index cff936b..d726838 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -76,10 +76,12 @@ IGNORED_ERRORS = { ], 'aggregation': [ 'Incompatible types in assignment (expression has type "QuerySet[Any]", variable has type "List[Any]")', - '"as_sql" undefined in superclass' + '"as_sql" undefined in superclass', + 'Incompatible types in assignment (expression has type "FlatValuesListIterable", variable has type "ValuesListIterable")' ], 'aggregation_regress': [ - 'Incompatible types in assignment (expression has type "List[str]", variable has type "QuerySet[Author]")' + 'Incompatible types in assignment (expression has type "List[str]", variable has type "QuerySet[Author]")', + 'Incompatible types in assignment (expression has type "FlatValuesListIterable", variable has type "QuerySet[Any]")' ], 'apps': [ 'Incompatible types in assignment (expression has type "str", target has type "type")',