diff --git a/django-stubs/db/migrations/state.pyi b/django-stubs/db/migrations/state.pyi index fbdb97b..0b84403 100644 --- a/django-stubs/db/migrations/state.pyi +++ b/django-stubs/db/migrations/state.pyi @@ -19,6 +19,12 @@ class AppConfigStub: def import_models(self) -> None: ... class ModelState: + name: str + app_label: str + fields: List[Tuple[str, Field]] + options: Optional[Dict[str, Any]] = ... + bases: Optional[Tuple[Type[Model]]] = ... + managers: Optional[List[Tuple[str, Manager]]] = ... def __init__( self, app_label: str, @@ -33,9 +39,9 @@ class ModelState: @classmethod def from_model(cls, model: Type[Model], exclude_rels: bool = ...) -> ModelState: ... def get_field_by_name(self, name: str) -> Field: ... - @cached_property + @property def name_lower(self) -> str: ... - def render(self, apps: StateApps) -> Any: ... + def render(self, apps: Apps) -> Any: ... class ProjectState: is_delayed: bool @@ -45,7 +51,7 @@ class ProjectState: self, models: Optional[Dict[Tuple[str, str], ModelState]] = ..., real_apps: Optional[List[str]] = ... ) -> None: ... def add_model(self, model_state: ModelState) -> None: ... - @cached_property + @property def apps(self) -> StateApps: ... def clear_delayed_apps_cache(self) -> None: ... def clone(self) -> ProjectState: ... diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index 62c594f..a3fbbc7 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -5,6 +5,7 @@ from django.db.models.query_utils import RegisterLookupMixin from django.db.models.expressions import F, Combinable from django.forms import Widget, Field as FormField +from .mixins import NOT_PROVIDED as NOT_PROVIDED _Choice = Tuple[Any, str] _ChoiceNamedGroup = Tuple[str, Iterable[_Choice]] diff --git a/django-stubs/db/models/query.pyi b/django-stubs/db/models/query.pyi index 655441d..836b2a5 100644 --- a/django-stubs/db/models/query.pyi +++ b/django-stubs/db/models/query.pyi @@ -63,7 +63,9 @@ class QuerySet(Iterable[_T], Sized): def latest(self, *fields: Any, field_name: Optional[Any] = ...) -> _T: ... def first(self) -> Optional[_T]: ... def last(self) -> Optional[_T]: ... - def in_bulk(self, id_list: Any = ..., *, field_name: str = ...) -> Dict[Union[int, str], models.Model]: ... + def in_bulk( + self, id_list: Any = ..., *, field_name: str = ..., **kwargs: Any + ) -> Dict[Union[int, str], models.Model]: ... def delete(self) -> Tuple[int, Dict[str, int]]: ... def update(self, **kwargs: Any) -> int: ... def _update(self, values: Any) -> Optional[Any]: ... diff --git a/django-stubs/db/models/sql/query.pyi b/django-stubs/db/models/sql/query.pyi index c6664db..95a262b 100644 --- a/django-stubs/db/models/sql/query.pyi +++ b/django-stubs/db/models/sql/query.pyi @@ -1,17 +1,15 @@ import collections from collections import OrderedDict, namedtuple -from datetime import datetime -from decimal import Decimal -from typing import Any, Callable, Dict, Iterator, List, Optional, Set, Tuple, Type, Union -from uuid import UUID +from typing import Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, Union -from django.db.models.sql.datastructures import BaseTable - -from django.db.models import Model, Field, Q, FilteredRelation, Expression, QuerySet +from django.db.models.lookups import Lookup from django.db.models.query_utils import PathInfo from django.db.models.sql.compiler import SQLCompiler +from django.db.models.sql.datastructures import BaseTable from django.db.models.sql.where import WhereNode +from django.db.models import Expression, Field, FilteredRelation, Model, Q, QuerySet + JoinInfo = namedtuple("JoinInfo", ["final_field", "targets", "opts", "joins", "path", "transform_function"]) class RawQuery: @@ -55,9 +53,7 @@ class Query: select_for_update_nowait: bool = ... select_for_update_skip_locked: bool = ... select_for_update_of: Tuple = ... - select_related: Union[ - Dict[str, Dict[str, Dict[str, Dict[str, Dict[str, Dict[str, Dict[str, Dict[Any, Any]]]]]]]], bool - ] = ... + select_related: Union[Dict[str, Any], bool] = ... max_depth: int = ... values_select: Tuple = ... annotation_select_mask: Optional[Set[str]] = ... @@ -178,6 +174,7 @@ class Query: def set_values(self, fields: Union[List[str], Tuple]) -> None: ... def trim_start(self, names_with_path: List[Tuple[str, List[PathInfo]]]) -> Tuple[str, bool]: ... def is_nullable(self, field: Field) -> bool: ... + def build_lookup(self, lookups: Sequence[str], lhs: Query, rhs: Optional[Query]) -> Lookup: ... class JoinPromoter: connector: str = ... diff --git a/django-stubs/test/runner.pyi b/django-stubs/test/runner.pyi index f63451e..98a18bd 100644 --- a/django-stubs/test/runner.pyi +++ b/django-stubs/test/runner.pyi @@ -1,7 +1,7 @@ import logging from argparse import ArgumentParser from io import StringIO -from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union +from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union, Sequence from unittest import TestCase, TextTestResult, TestSuite from django.db.backends.base.base import BaseDatabaseWrapper @@ -38,6 +38,7 @@ class RemoteTestResult: @property def test_index(self): ... def check_picklable(self, test: Any, err: Any) -> None: ... + def _confirm_picklable(self, obj: Any) -> None: ... def check_subtest_picklable(self, test: Any, subtest: Any) -> None: ... def stop_if_failfast(self) -> None: ... def stop(self) -> None: ... @@ -109,10 +110,7 @@ class DiscoverRunner: def add_arguments(cls, parser: ArgumentParser) -> None: ... def setup_test_environment(self, **kwargs: Any) -> None: ... def build_suite( - self, - test_labels: Union[List[str], Tuple[str, str]] = ..., - extra_tests: Optional[List[Any]] = ..., - **kwargs: Any + self, test_labels: Sequence[str] = ..., extra_tests: Optional[List[Any]] = ..., **kwargs: Any ) -> TestSuite: ... def setup_databases(self, **kwargs: Any) -> List[Tuple[BaseDatabaseWrapper, str, bool]]: ... def get_resultclass(self) -> Optional[Type[DebugSQLTextTestResult]]: ... diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 7418991..0cc9831 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -161,7 +161,13 @@ IGNORED_ERRORS = { 'Too few arguments for "render" of "Template"' ], 'test_runner': [ - 'Value of type "TestSuite" is not indexable' + 'Value of type "TestSuite" is not indexable', + '"TestSuite" has no attribute "_tests"', + 'Argument "result" to "run" of "TestCase" has incompatible type "RemoteTestResult"; expected "Optional[TestResult]"', + 'Item "TestSuite" of "Union[TestCase, TestSuite]" has no attribute "id"', + 'MockTestRunner', + 'Incompatible types in assignment (expression has type "Tuple[Union[TestCase, TestSuite], ...]", ' + + 'variable has type "TestSuite")' ], 'urlpatterns': [ '"object" has no attribute "__iter__"; maybe "__str__" or "__dir__"? (not iterable)', @@ -285,7 +291,7 @@ TESTS_DIRS = [ # TODO: 'invalid_models_tests', 'known_related_objects', # TODO: 'logging_tests', - # TODO: 'lookup', + 'lookup', 'm2m_and_m2o', 'm2m_intermediary', 'm2m_multiple', @@ -376,7 +382,7 @@ TESTS_DIRS = [ 'test_client', 'test_client_regress', 'test_exceptions', - # TODO: 'test_runner', + 'test_runner', 'test_runner_apps', 'test_utils', 'timezones',