From 2525b5b89fb69280d5e5b55d258c6cd46461ef25 Mon Sep 17 00:00:00 2001 From: Oleg Nykolyn <juravel2@gmail.com> Date: Sat, 26 Jan 2019 16:32:46 +0200 Subject: [PATCH 1/4] Add missing re-imports to django.db.models. --- django-stubs/db/models/__init__.pyi | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/django-stubs/db/models/__init__.pyi b/django-stubs/db/models/__init__.pyi index 691d945f2..0ccd8ace8 100644 --- a/django-stubs/db/models/__init__.pyi +++ b/django-stubs/db/models/__init__.pyi @@ -1,6 +1,15 @@ from .base import Model as Model -from .aggregates import Aggregate as Aggregate, Sum as Sum, Variance as Variance, Count as Count, Max as Max +from .aggregates import ( + Aggregate as Aggregate, + Avg as Avg, + Count as Count, + Max as Max, + Min as Min, + StdDev as StdDev, + Sum as Sum, + Variance as Variance, +) from .fields import ( AutoField as AutoField, @@ -46,7 +55,12 @@ from .deletion import ( PROTECT as PROTECT, ) -from .query import QuerySet as QuerySet, RawQuerySet as RawQuerySet +from .query import ( + Prefetch as Prefetch, + QuerySet as QuerySet, + RawQuerySet as RawQuerySet, + prefetch_related_objects as prefetch_related_objects, +) from .query_utils import Q as Q, FilteredRelation as FilteredRelation From 255e4af9117a4ba44f31370a60e3d3979147bc4c Mon Sep 17 00:00:00 2001 From: Oleg Nykolyn <juravel2@gmail.com> Date: Thu, 31 Jan 2019 20:29:15 +0200 Subject: [PATCH 2/4] Add annotations for Prefetch, prefetch_related_objects. --- django-stubs/db/models/query.pyi | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/django-stubs/db/models/query.pyi b/django-stubs/db/models/query.pyi index 6ee30aa1e..5dec09d7d 100644 --- a/django-stubs/db/models/query.pyi +++ b/django-stubs/db/models/query.pyi @@ -122,3 +122,25 @@ class RawQuerySet(Iterable[_T], Sized): def prefetch_related(self, *lookups: Any) -> RawQuerySet[_T]: ... def resolve_model_init_order(self) -> Tuple[List[str], List[int], List[Tuple[str, int]]]: ... def using(self, alias: Optional[str]) -> RawQuerySet[_T]: ... + +class Prefetch(object): + def __init__(self, lookup, queryset=None, to_attr=None): + # `prefetch_through` is the path we traverse to perform the prefetch. + self.prefetch_through = lookup + # `prefetch_to` is the path to the attribute that stores the result. + self.prefetch_to = lookup + if queryset is not None and not issubclass(queryset._iterable_class, ModelIterable): + raise ValueError('Prefetch querysets cannot use values().') + if to_attr: + self.prefetch_to = LOOKUP_SEP.join(lookup.split(LOOKUP_SEP)[:-1] + [to_attr]) + + self.queryset = queryset + self.to_attr = to_attr + + def __getstate__(self) -> Dict[str, Any]: ... + def add_prefix(self, prefix: str) -> None: ... + def get_current_prefetch_to(self, level: int) -> str: ... + def get_current_to_attr(self, level: int) -> Tuple[str,str]: ... + def get_current_queryset(self, level) -> Optional[QuerySet]: ... + +def prefetch_related_objects(model_instances: Iterable[_T], *related_lookups: str) -> None: ... From 3ccecebe3fcbc27cafee8c63fa586019befb7251 Mon Sep 17 00:00:00 2001 From: Oleg Nykolyn <juravel2@gmail.com> Date: Thu, 31 Jan 2019 21:35:35 +0200 Subject: [PATCH 3/4] Fix and uncomment tests. --- django-stubs/db/models/query.pyi | 19 +++++-------------- scripts/typecheck_tests.py | 4 +++- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/django-stubs/db/models/query.pyi b/django-stubs/db/models/query.pyi index f62929fd8..47d38f2b7 100644 --- a/django-stubs/db/models/query.pyi +++ b/django-stubs/db/models/query.pyi @@ -144,26 +144,17 @@ class RawQuerySet(Iterable[_T], Sized): def using(self, alias: Optional[str]) -> RawQuerySet[_T]: ... class Prefetch(object): - def __init__(self, lookup, queryset=None, to_attr=None): - # `prefetch_through` is the path we traverse to perform the prefetch. - self.prefetch_through = lookup - # `prefetch_to` is the path to the attribute that stores the result. - self.prefetch_to = lookup - if queryset is not None and not issubclass(queryset._iterable_class, ModelIterable): - raise ValueError('Prefetch querysets cannot use values().') - if to_attr: - self.prefetch_to = LOOKUP_SEP.join(lookup.split(LOOKUP_SEP)[:-1] + [to_attr]) - - self.queryset = queryset - self.to_attr = to_attr - + def __init__(self, lookup: str, queryset: Optional[QuerySet]=None, to_attr: Optional[str]=None) -> None: ... def __getstate__(self) -> Dict[str, Any]: ... def add_prefix(self, prefix: str) -> None: ... def get_current_prefetch_to(self, level: int) -> str: ... def get_current_to_attr(self, level: int) -> Tuple[str,str]: ... def get_current_queryset(self, level) -> Optional[QuerySet]: ... -def prefetch_related_objects(model_instances: Iterable[_T], *related_lookups: str) -> None: ... +def prefetch_related_objects(model_instances: Iterable[_T], *related_lookups: Union[str, Prefetch]) -> None: ... +def get_prefetcher(instance: _T, through_attr: str, to_attr: str) -> Tuple[Any, Any, bool, bool]: ... + +class ModelIterable(Iterable[_T]): ... class InstanceCheckMeta(type): ... class EmptyQuerySet(metaclass=InstanceCheckMeta): ... diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 1b10eb7ba..7f2720491 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -55,6 +55,8 @@ 'Argument 1 to "bytes"', '"full_clean" of "Model" does not return a value', '"object" not callable', + 'Item "GenericForeignKey" of "Union[GenericForeignKey, Model, None]" has no attribute "read_by"', + 'Item "Model" of "Union[GenericForeignKey, Model, None]" has no attribute "read_by"', re.compile('Cannot determine type of \'(objects|stuff|specimens|normal_manager)\''), re.compile(r'"Callable\[\[(Any(, )?)+\], Any\]" has no attribute'), re.compile(r'"HttpResponseBase" has no attribute "[A-Za-z_]+"'), @@ -215,9 +217,9 @@ 'or_lookups', 'order_with_respect_to', 'ordering', + 'prefetch_related', 'pagination', # TODO: 'postgres_tests', - # TODO: 'prefetch_related', 'project_template', 'properties', 'proxy_model_inheritance', From 7a7f68ede4d52705d0d8bc4a14001deec037d84f Mon Sep 17 00:00:00 2001 From: Oleg Nykolyn <juravel2@gmail.com> Date: Thu, 31 Jan 2019 21:44:32 +0200 Subject: [PATCH 4/4] Fix formatting. --- django-stubs/db/models/query.pyi | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/django-stubs/db/models/query.pyi b/django-stubs/db/models/query.pyi index 47d38f2b7..23ab5cfbc 100644 --- a/django-stubs/db/models/query.pyi +++ b/django-stubs/db/models/query.pyi @@ -144,17 +144,16 @@ class RawQuerySet(Iterable[_T], Sized): def using(self, alias: Optional[str]) -> RawQuerySet[_T]: ... class Prefetch(object): - def __init__(self, lookup: str, queryset: Optional[QuerySet]=None, to_attr: Optional[str]=None) -> None: ... + def __init__(self, lookup: str, queryset: Optional[QuerySet] = None, to_attr: Optional[str] = None) -> None: ... def __getstate__(self) -> Dict[str, Any]: ... def add_prefix(self, prefix: str) -> None: ... def get_current_prefetch_to(self, level: int) -> str: ... - def get_current_to_attr(self, level: int) -> Tuple[str,str]: ... + def get_current_to_attr(self, level: int) -> Tuple[str, str]: ... def get_current_queryset(self, level) -> Optional[QuerySet]: ... def prefetch_related_objects(model_instances: Iterable[_T], *related_lookups: Union[str, Prefetch]) -> None: ... def get_prefetcher(instance: _T, through_attr: str, to_attr: str) -> Tuple[Any, Any, bool, bool]: ... class ModelIterable(Iterable[_T]): ... - class InstanceCheckMeta(type): ... class EmptyQuerySet(metaclass=InstanceCheckMeta): ...