From 287c64d6fb26b605b8b161b75232d54191cdf642 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 12 Nov 2019 05:17:36 +0300 Subject: [PATCH] Pin to 0.740 and fix CI (#225) * update django sources * pin mypy version, update to 0.740 * fix tests typechecking * fix lint --- django-sources | 2 +- django-stubs/apps/config.pyi | 5 +- .../contrib/admin/templatetags/admin_list.pyi | 2 +- django-stubs/contrib/staticfiles/finders.pyi | 2 +- django-stubs/db/backends/base/base.pyi | 2 +- django-stubs/db/backends/base/operations.pyi | 4 +- django-stubs/db/models/fields/__init__.pyi | 8 +- django-stubs/db/models/lookups.pyi | 6 +- django-stubs/db/models/manager.pyi | 2 +- django-stubs/db/models/query_utils.pyi | 7 +- django-stubs/db/models/sql/compiler.pyi | 4 +- django-stubs/http/request.pyi | 2 +- django-stubs/http/response.pyi | 2 +- django-stubs/test/client.pyi | 50 +++---- django-stubs/test/testcases.pyi | 8 +- django-stubs/utils/tree.pyi | 12 +- scripts/enabled_test_modules.py | 134 +++++++++++++----- setup.py | 2 +- .../managers/querysets/test_filter.yml | 14 +- 19 files changed, 160 insertions(+), 108 deletions(-) diff --git a/django-sources b/django-sources index f452d42..612c2d1 160000 --- a/django-sources +++ b/django-sources @@ -1 +1 @@ -Subproject commit f452d4232e1c14269bf2f1bd234d6e4ef462dc55 +Subproject commit 612c2d166c9048c59ee241ce4ba89858aa65665d diff --git a/django-stubs/apps/config.pyi b/django-stubs/apps/config.pyi index 414f108..aa3fb80 100644 --- a/django-stubs/apps/config.pyi +++ b/django-stubs/apps/config.pyi @@ -1,5 +1,6 @@ from typing import Any, Iterator, Type, Optional, Dict +from django.apps.registry import Apps from django.db.models.base import Model MODELS_MODULE_NAME: str @@ -7,11 +8,11 @@ MODELS_MODULE_NAME: str class AppConfig: name: str = ... module: Optional[Any] = ... - apps: None = ... + apps: Optional[Apps] = ... label: str = ... verbose_name: str = ... path: str = ... - models_module: None = ... + models_module: Optional[str] = ... models: Dict[str, Type[Model]] = ... def __init__(self, app_name: str, app_module: Optional[Any]) -> None: ... @classmethod diff --git a/django-stubs/contrib/admin/templatetags/admin_list.pyi b/django-stubs/contrib/admin/templatetags/admin_list.pyi index 9d8ed88..8218f37 100644 --- a/django-stubs/contrib/admin/templatetags/admin_list.pyi +++ b/django-stubs/contrib/admin/templatetags/admin_list.pyi @@ -27,7 +27,7 @@ class ResultList(list): def results(cl: ChangeList) -> Iterator[ResultList]: ... def result_hidden_fields(cl: ChangeList) -> Iterator[BoundField]: ... def result_list( - cl: ChangeList + cl: ChangeList, ) -> Dict[ str, Union[List[Dict[str, Optional[Union[int, str]]]], List[ResultList], List[BoundField], ChangeList, int] ]: ... diff --git a/django-stubs/contrib/staticfiles/finders.pyi b/django-stubs/contrib/staticfiles/finders.pyi index eb6bc13..8645a29 100644 --- a/django-stubs/contrib/staticfiles/finders.pyi +++ b/django-stubs/contrib/staticfiles/finders.pyi @@ -37,7 +37,7 @@ def get_finders() -> Iterator[BaseFinder]: ... def get_finder(import_path: Literal["django.contrib.staticfiles.finders.FileSystemFinder"]) -> FileSystemFinder: ... @overload def get_finder( - import_path: Literal["django.contrib.staticfiles.finders.AppDirectoriesFinder"] + import_path: Literal["django.contrib.staticfiles.finders.AppDirectoriesFinder"], ) -> AppDirectoriesFinder: ... @overload def get_finder(import_path: str) -> BaseFinder: ... diff --git a/django-stubs/db/backends/base/base.pyi b/django-stubs/db/backends/base/base.pyi index 29a2883..eafdad5 100644 --- a/django-stubs/db/backends/base/base.pyi +++ b/django-stubs/db/backends/base/base.pyi @@ -20,7 +20,7 @@ class BaseDatabaseWrapper: ops: Any = ... vendor: str = ... display_name: str = ... - SchemaEditorClass: Any = ... + SchemaEditorClass: Optional[BaseDatabaseSchemaEditor] = ... client_class: Any = ... creation_class: Any = ... features_class: Any = ... diff --git a/django-stubs/db/backends/base/operations.pyi b/django-stubs/db/backends/base/operations.pyi index 43926e4..fa9905c 100644 --- a/django-stubs/db/backends/base/operations.pyi +++ b/django-stubs/db/backends/base/operations.pyi @@ -1,4 +1,4 @@ -from datetime import date, datetime, timedelta +from datetime import date, datetime, timedelta, time from decimal import Decimal from typing import Any, List, Optional, Sequence, Tuple, Type, Union @@ -79,7 +79,7 @@ class BaseDatabaseOperations: def adapt_unknown_value(self, value: Any) -> Any: ... def adapt_datefield_value(self, value: Optional[date]) -> Optional[str]: ... def adapt_datetimefield_value(self, value: Optional[datetime]) -> Optional[str]: ... - def adapt_timefield_value(self, value: Optional[datetime]) -> Optional[str]: ... + def adapt_timefield_value(self, value: Optional[Union[datetime, time]]) -> Optional[str]: ... def adapt_decimalfield_value( self, value: Optional[Decimal], max_digits: Optional[int] = ..., decimal_places: Optional[int] = ... ) -> Optional[str]: ... diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index 1e7dd30..b4c3be0 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -64,6 +64,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]): choices: Optional[_FieldChoices] = ... db_column: Optional[str] column: str + default: Any error_messages: _ErrorMessagesToOverride def __init__( self, @@ -132,7 +133,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]): class IntegerField(Field[_ST, _GT]): _pyi_private_set_type: Union[float, int, str, Combinable] _pyi_private_get_type: int - _pyi_lookup_exact_type: int + _pyi_lookup_exact_type: Union[str, int] class PositiveIntegerRelDbTypeMixin: def rel_db_type(self, connection: Any): ... @@ -180,7 +181,7 @@ class DecimalField(Field[_ST, _GT]): class AutoField(Field[_ST, _GT]): _pyi_private_set_type: Union[Combinable, int, str] _pyi_private_get_type: int - _pyi_lookup_exact_type: int + _pyi_lookup_exact_type: Union[str, int] class CharField(Field[_ST, _GT]): _pyi_private_set_type: Union[str, int, Combinable] @@ -389,7 +390,8 @@ class FilePathField(Field[_ST, _GT]): error_messages: Optional[_ErrorMessagesToOverride] = ..., ): ... -class BinaryField(Field[_ST, _GT]): ... +class BinaryField(Field[_ST, _GT]): + _pyi_private_get_type: bytes class DurationField(Field[_ST, _GT]): _pyi_private_get_type: timedelta diff --git a/django-stubs/db/models/lookups.pyi b/django-stubs/db/models/lookups.pyi index ddf341f..6bdf9d9 100644 --- a/django-stubs/db/models/lookups.pyi +++ b/django-stubs/db/models/lookups.pyi @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, Iterable, List, Optional, Tuple, Type, Union, Mapping, TypeVar, Generic, Sequence +from typing import Any, Iterable, List, Optional, Tuple, Type, Union, Mapping, TypeVar, Generic from django.db.backends.sqlite3.base import DatabaseWrapper from django.db.models.expressions import Expression, Func @@ -31,9 +31,7 @@ class Lookup(Generic[_T]): def process_lhs( self, compiler: SQLCompiler, connection: DatabaseWrapper, lhs: Optional[Expression] = ... ) -> Tuple[str, List[Union[int, str]]]: ... - def process_rhs( - self, compiler: SQLCompiler, connection: DatabaseWrapper - ) -> Tuple[str, Sequence[Union[int, str]]]: ... + def process_rhs(self, compiler: SQLCompiler, connection: DatabaseWrapper) -> Tuple[str, List[Union[int, str]]]: ... def rhs_is_direct_value(self) -> bool: ... def relabeled_clone(self: _T, relabels: Mapping[str, str]) -> _T: ... def get_group_by_cols(self) -> List[Expression]: ... diff --git a/django-stubs/db/models/manager.pyi b/django-stubs/db/models/manager.pyi index ac6fa6b..aef2baf 100644 --- a/django-stubs/db/models/manager.pyi +++ b/django-stubs/db/models/manager.pyi @@ -10,7 +10,7 @@ class BaseManager(QuerySet[_T]): auto_created: bool = ... use_in_migrations: bool = ... name: str = ... - model: Type[Model] = ... + model: Type[_T] = ... db: str def __init__(self) -> None: ... def deconstruct(self) -> Tuple[bool, str, None, Tuple, Dict[str, int]]: ... diff --git a/django-stubs/db/models/query_utils.pyi b/django-stubs/db/models/query_utils.pyi index 45a4944..e0bdbc3 100644 --- a/django-stubs/db/models/query_utils.pyi +++ b/django-stubs/db/models/query_utils.pyi @@ -1,5 +1,5 @@ from collections import namedtuple -from typing import Any, Collection, Dict, Iterator, List, Mapping, Optional, Sequence, Set, Tuple, Type, Union +from typing import Any, Collection, Dict, Iterator, List, Mapping, Optional, Sequence, Set, Tuple, Type from django.db.models.base import Model from django.db.models.fields.mixins import FieldCacheMixin @@ -23,12 +23,8 @@ class QueryWrapper: def as_sql(self, compiler: SQLCompiler = ..., connection: Any = ...) -> Any: ... class Q(tree.Node): - children: Union[List[Dict[str, str]], List[Tuple[str, Any]], List[Q]] - connector: str - negated: bool AND: str = ... OR: str = ... - default: Any = ... conditional: bool = ... def __init__(self, *args: Any, **kwargs: Any) -> None: ... def __or__(self, other: Any) -> Q: ... @@ -47,7 +43,6 @@ class Q(tree.Node): class DeferredAttribute: field_name: str = ... def __init__(self, field_name: str) -> None: ... - def __get__(self, instance: Optional[Model], cls: Type[Model] = ...) -> Any: ... class RegisterLookupMixin: lookup_name: str diff --git a/django-stubs/db/models/sql/compiler.pyi b/django-stubs/db/models/sql/compiler.pyi index 30b842e..c5aa475 100644 --- a/django-stubs/db/models/sql/compiler.pyi +++ b/django-stubs/db/models/sql/compiler.pyi @@ -25,7 +25,7 @@ class SQLCompiler: def setup_query(self) -> None: ... has_extra_select: Any = ... def pre_sql_setup( - self + self, ) -> Tuple[ List[Tuple[Expression, Tuple[str, Union[List[Any], Tuple[str, str]]], None]], List[Tuple[Expression, Tuple[str, List[Union[int, str]], bool]]], @@ -40,7 +40,7 @@ class SQLCompiler: self, expressions: List[Expression], having: Union[List[Expression], Tuple] ) -> List[Expression]: ... def get_select( - self + self, ) -> Tuple[ List[Tuple[Expression, Tuple[str, List[Union[int, str]]], Optional[str]]], Optional[Dict[str, Any]], diff --git a/django-stubs/http/request.pyi b/django-stubs/http/request.pyi index 8f8a7aa..1405c9e 100644 --- a/django-stubs/http/request.pyi +++ b/django-stubs/http/request.pyi @@ -63,7 +63,7 @@ class HttpRequest(BytesIO): self, key: str, default: Any = ..., salt: str = ..., max_age: Optional[int] = ... ) -> Optional[str]: ... def get_raw_uri(self) -> str: ... - def build_absolute_uri(self, location: str = ...) -> str: ... + def build_absolute_uri(self, location: Optional[str] = ...) -> str: ... @property def scheme(self) -> Optional[str]: ... def is_secure(self) -> bool: ... diff --git a/django-stubs/http/response.pyi b/django-stubs/http/response.pyi index 1804fed..4c4b32e 100644 --- a/django-stubs/http/response.pyi +++ b/django-stubs/http/response.pyi @@ -63,7 +63,7 @@ class HttpResponseBase(Iterable[Any]): class HttpResponse(HttpResponseBase): client: Client - context: Optional[Context] + context: Context csrf_cookie_set: bool redirect_chain: List[Tuple[str, int]] request: Dict[str, Any] diff --git a/django-stubs/test/client.pyi b/django-stubs/test/client.pyi index 00e043c..d8853d0 100644 --- a/django-stubs/test/client.pyi +++ b/django-stubs/test/client.pyi @@ -9,6 +9,8 @@ from django.http.cookie import SimpleCookie from django.http.request import HttpRequest from django.http.response import HttpResponse, HttpResponseBase +from django.core.handlers.wsgi import WSGIRequest + BOUNDARY: str = ... MULTIPART_CONTENT: str = ... CONTENT_TYPE_RE: Pattern = ... @@ -40,13 +42,13 @@ class RequestFactory: cookies: SimpleCookie = ... errors: BytesIO = ... def __init__(self, *, json_encoder: Any = ..., **defaults: Any) -> None: ... - def request(self, **request: Any) -> HttpRequest: ... - def get(self, path: str, data: Any = ..., secure: bool = ..., **extra: Any) -> HttpRequest: ... + def request(self, **request: Any) -> WSGIRequest: ... + def get(self, path: str, data: Any = ..., secure: bool = ..., **extra: Any) -> WSGIRequest: ... def post( self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpRequest: ... - def head(self, path: str, data: Any = ..., secure: bool = ..., **extra: Any) -> HttpRequest: ... - def trace(self, path: str, secure: bool = ..., **extra: Any) -> HttpRequest: ... + ) -> WSGIRequest: ... + def head(self, path: str, data: Any = ..., secure: bool = ..., **extra: Any) -> WSGIRequest: ... + def trace(self, path: str, secure: bool = ..., **extra: Any) -> WSGIRequest: ... def options( self, path: str, @@ -54,16 +56,16 @@ class RequestFactory: content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpRequest: ... + ) -> WSGIRequest: ... def put( self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpRequest: ... + ) -> WSGIRequest: ... def patch( self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpRequest: ... + ) -> WSGIRequest: ... def delete( self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpRequest: ... + ) -> WSGIRequest: ... def generic( self, method: str, @@ -72,7 +74,7 @@ class RequestFactory: content_type: Optional[str] = ..., secure: bool = ..., **extra: Any - ) -> HttpRequest: ... + ) -> WSGIRequest: ... class Client: json_encoder: Type[DjangoJSONEncoder] = ... @@ -82,13 +84,11 @@ class Client: handler: ClientHandler = ... exc_info: None = ... def __init__(self, enforce_csrf_checks: bool = ..., **defaults: Any) -> None: ... - def request(self, **request: Any) -> HttpResponse: ... - def get(self, path: str, data: Any = ..., secure: bool = ..., **extra: Any) -> HttpResponse: ... - def post( - self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpResponse: ... - def head(self, path: str, data: Any = ..., secure: bool = ..., **extra: Any) -> HttpResponse: ... - def trace(self, path: str, secure: bool = ..., **extra: Any) -> HttpResponse: ... + def request(self, **request: Any) -> Any: ... + def get(self, path: str, data: Any = ..., secure: bool = ..., **extra: Any) -> Any: ... + def post(self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any) -> Any: ... + def head(self, path: str, data: Any = ..., secure: bool = ..., **extra: Any) -> Any: ... + def trace(self, path: str, secure: bool = ..., **extra: Any) -> Any: ... def options( self, path: str, @@ -96,16 +96,10 @@ class Client: content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpResponse: ... - def put( - self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpResponse: ... - def patch( - self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpResponse: ... - def delete( - self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any - ) -> HttpResponse: ... + ) -> Any: ... + def put(self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any) -> Any: ... + def patch(self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any) -> Any: ... + def delete(self, path: str, data: Any = ..., content_type: str = ..., secure: bool = ..., **extra: Any) -> Any: ... def generic( self, method: str, @@ -114,7 +108,7 @@ class Client: content_type: Optional[str] = ..., secure: bool = ..., **extra: Any - ) -> HttpResponse: ... + ) -> Any: ... def store_exc_info(self, **kwargs: Any) -> None: ... @property def session(self) -> SessionBase: ... diff --git a/django-stubs/test/testcases.pyi b/django-stubs/test/testcases.pyi index 73ae5b5..c7123a2 100644 --- a/django-stubs/test/testcases.pyi +++ b/django-stubs/test/testcases.pyi @@ -1,7 +1,7 @@ import threading import unittest from datetime import date -from typing import Any, Callable, Dict, Iterator, List, Optional, Set, Tuple, Type, Union +from typing import Any, Callable, Dict, Iterator, List, Optional, Set, Tuple, Type, Union, ClassVar from django.core.exceptions import ImproperlyConfigured from django.core.handlers.wsgi import WSGIHandler @@ -47,7 +47,8 @@ class SimpleTestCase(unittest.TestCase): client_class: Any = ... client: Client allow_database_queries: bool = ... - databases: Set[str] = ... + # TODO: str -> Literal['__all__'] + databases: Union[Set[str], str] = ... def __call__(self, result: Optional[unittest.TestResult] = ...) -> None: ... def settings(self, **kwargs: Any) -> Any: ... def modify_settings(self, **kwargs: Any) -> Any: ... @@ -198,13 +199,12 @@ class LiveServerThread(threading.Thread): def terminate(self) -> None: ... class LiveServerTestCase(TransactionTestCase): + live_server_url: ClassVar[str] host: str = ... port: int = ... server_thread_class: Type[Any] = ... server_thread: Any static_handler: Any = ... - @classmethod - def live_server_url(cls): ... class SerializeMixin: lockfile: Any = ... diff --git a/django-stubs/utils/tree.pyi b/django-stubs/utils/tree.pyi index 74f9690..3f11e11 100644 --- a/django-stubs/utils/tree.pyi +++ b/django-stubs/utils/tree.pyi @@ -1,16 +1,16 @@ -from typing import Any, Dict, Iterable, Optional, Tuple, Union, Sequence +from typing import Any, Dict, Iterable, Optional, Tuple, Union, Sequence, List from django.db.models.sql.where import NothingNode +_NodeChildren = Iterable[Union["Node", NothingNode, Sequence[Any]]] + class Node: - default: str = ... + children: List[Any] + default: Any = ... connector: str = ... negated: bool = ... def __init__( - self, - children: Optional[Iterable[Union[Node, NothingNode, Sequence[Any]]]] = ..., - connector: Optional[str] = ..., - negated: bool = ..., + self, children: Optional[_NodeChildren] = ..., connector: Optional[str] = ..., negated: bool = ..., ) -> None: ... def __deepcopy__(self, memodict: Dict[Any, Any]) -> Node: ... def __len__(self) -> int: ... diff --git a/scripts/enabled_test_modules.py b/scripts/enabled_test_modules.py index 44f5a28..cdfeb57 100644 --- a/scripts/enabled_test_modules.py +++ b/scripts/enabled_test_modules.py @@ -11,7 +11,7 @@ IGNORED_MODULES = {'schema', 'gis_tests', 'admin_widgets', 'admin_filters', 'mig 'sites_tests', 'inline_formsets', 'foreign_object', 'cache', 'test_client', 'test_client_regress'} MOCK_OBJECTS = ['MockRequest', 'MockCompiler', 'modelz', 'call_count', 'call_args_list', - 'call_args', 'MockUser', 'Xtemplate', 'DummyRequest', 'DummyUser', 'MinimalUser'] + 'call_args', 'MockUser', 'Xtemplate', 'DummyRequest', 'DummyUser', 'MinimalUser', 'DummyNode'] EXTERNAL_MODULES = ['psycopg2', 'PIL', 'selenium', 'oracle', 'mysql', 'sqlite3', 'sqlparse', 'tblib', 'numpy', 'bcrypt', 'argon2', 'xml.dom'] IGNORED_ERRORS = { @@ -25,8 +25,7 @@ IGNORED_ERRORS = { 'Cannot assign to a type', '"HttpResponseBase" has no attribute', '"object" has no attribute', - re.compile(r'"Callable\[(\[(Any(, )?)*((, )?VarArg\(Any\))?((, )?KwArg\(Any\))?\]|\.\.\.), Any\]" ' - r'has no attribute'), + re.compile(r'"Callable\[.+, Any\]" has no attribute'), 'has no attribute "deconstruct"', # private members re.compile(r'has no attribute ("|\')_[a-zA-Z_]+("|\')'), @@ -35,7 +34,7 @@ IGNORED_ERRORS = { re.compile(r"Expression of type '.*' is not supported"), 'has incompatible type "object"', 'undefined in superclass', - 'Argument after ** must be a mapping, not "object"', + 'Argument after ** must be a mapping', 'note:', re.compile(r'Item "None" of "[a-zA-Z_ ,\[\]]+" has no attribute'), '"Optional[List[_Record]]"', @@ -61,7 +60,12 @@ IGNORED_ERRORS = { # TODO: multitable inheritance 'ptr', 'Incompatible types in assignment (expression has type "Callable[', - 'SimpleLazyObject' + 'SimpleLazyObject', + 'Test', + 'Mixin" has no attribute', + 'Incompatible types in string interpolation', + '"None" has no attribute', + 'has no attribute "assert', ], 'aggregation': [ re.compile(r'got "Optional\[(Author|Publisher)\]", expected "Union\[(Author|Publisher), Combinable\]"'), @@ -83,6 +87,8 @@ IGNORED_ERRORS = { 'Unsupported left operand type for + ("Sequence[str]")', 'AuthenticationFormWithInactiveUsersOkay', 'Incompatible types in assignment (expression has type "Dict[str, Any]", variable has type "QueryDict")', + 'No overload variant of "int" matches argument type "AnonymousUser"', + 'expression has type "AnonymousUser", variable has type "User"', ], 'basic': [ 'Unexpected keyword argument "unknown_kwarg" for "refresh_from_db" of "Model"', @@ -93,42 +99,50 @@ IGNORED_ERRORS = { 'backends': [ '"DatabaseError" has no attribute "pgcode"' ], + 'builtin_server': [ + '"ServerHandler" has no attribute', + ], 'check_framework': [ 'base class "Model" defined the type as "Callable', + 'Value of type "Collection[str]" is not indexable', + 'Unsupported target for indexed assignment', ], 'constraints': [ 'Argument "condition" to "UniqueConstraint" has incompatible type "str"; expected "Optional[Q]"' ], 'contenttypes_tests': [ - # 'Item "Model" of "Union[GenericForeignKey, Model, None]" has no attribute' - 'base class "BaseOrderWithRespectToTests" defined the type as "None"' + '"FooWithBrokenAbsoluteUrl" has no attribute "unknown_field"', ], 'custom_lookups': [ - 'in base class "SQLFuncMixin"' + 'in base class "SQLFuncMixin"', + 'has no attribute "name"', ], 'custom_columns': [ "Cannot resolve keyword 'firstname' into field", ], 'custom_pk': [ - '"Employee" has no attribute "id"' + '"Employee" has no attribute "id"', ], 'custom_managers': [ 'Unsupported dynamic base class', 'Incompatible types in assignment (expression has type "CharField', - 'Item "Book" of "Optional[Book]" has no attribute "favorite_avg"' + 'Item "Book" of "Optional[Book]" has no attribute "favorite_avg"', ], 'csrf_tests': [ - 'Incompatible types in assignment (expression has type "property", ' + - 'base class "HttpRequest" defined the type as "QueryDict")' + 'expression has type "property", base class "HttpRequest" defined the type as "QueryDict"', + 'expression has type "Dict[, ]", variable has type "SessionBase"', ], 'dates': [ 'Too few arguments for "dates" of', ], + 'dbshell': [ + 'Incompatible types in assignment (expression has type "None"', + ], 'defer': [ 'Too many arguments for "refresh_from_db" of "Model"' ], 'delete': [ - 'Incompatible type for lookup \'pk\': (got "Optional[int]", expected "int")', + 'Incompatible type for lookup \'pk\': (got "Optional[int]", expected "Union[str, int]")', ], 'dispatch': [ 'Item "str" of "Union[ValueError, str]" has no attribute "args"' @@ -153,36 +167,48 @@ IGNORED_ERRORS = { 'file_uploads': [ 'has no attribute "content_type"', ], + 'file_storage': [ + 'Incompatible types in assignment (expression has type "None", variable has type "str")', + 'Property "base_url" defined in "FileSystemStorage" is read-only', + ], 'files': [ 'Incompatible types in assignment (expression has type "IOBase", variable has type "File")', + 'Argument 1 to "write" of "SpooledTemporaryFile"', + ], + 'filtered_relation': [ + 'has no attribute "name"', ], 'fixtures': [ 'Incompatible types in assignment (expression has type "int", target has type "Iterable[str]")', - 'Incompatible types in assignment (expression has type "SpyManager[Spy]"' + 'Incompatible types in assignment (expression has type "SpyManager[Spy]"', + ], + 'fixtures_regress': [ + 'Unsupported left operand type for + ("None")', ], 'from_db_value': [ - '"Cash" has no attribute' + '"Cash" has no attribute', + 'Argument 1 to "__str__" of "Decimal"', ], 'get_object_or_404': [ 'Argument 1 to "get_object_or_404" has incompatible type "str"; ' + 'expected "Union[Type[], QuerySet[]]"', 'Argument 1 to "get_list_or_404" has incompatible type "List[Type[Article]]"; ' + 'expected "Union[Type[], QuerySet[]]"', - 'CustomClass' + 'CustomClass', ], 'generic_relations': [ - "Cannot resolve keyword 'vegetable' into field" + "Cannot resolve keyword 'vegetable' into field", ], 'generic_relations_regress': [ - '"Link" has no attribute' + '"Link" has no attribute', ], 'httpwrappers': [ 'Argument 2 to "appendlist" of "QueryDict"', 'Incompatible types in assignment (expression has type "int", target has type "Union[str, List[str]]")', - 'Argument 1 to "fromkeys" of "QueryDict" has incompatible type "int"' + 'Argument 1 to "fromkeys" of "QueryDict" has incompatible type "int"', ], 'humanize_tests': [ - 'Argument 1 to "append" of "list" has incompatible type "None"; expected "str"' + 'Argument 1 to "append" of "list" has incompatible type "None"; expected "str"', ], 'lookup': [ 'Unexpected keyword argument "headline__startswith" for "in_bulk" of', @@ -190,18 +216,29 @@ IGNORED_ERRORS = { "Cannot resolve keyword 'pub_date_year' into field", "Cannot resolve keyword 'blahblah' into field", ], + 'logging_tests': [ + re.compile(r'Argument [0-9] to "makeRecord" of "Logger"'), + '"LogRecord" has no attribute "request"', + ], 'm2m_regress': [ "Cannot resolve keyword 'porcupine' into field", ], 'messages_tests': [ - 'List item 0 has incompatible type "Dict[str, Message]"; expected "Message"' + 'List item 0 has incompatible type "Dict[str, Message]"; expected "Message"', + 'Too many arguments', + 'CustomRequest', ], 'middleware': [ - '"HttpRequest" has no attribute' + re.compile(r'"(HttpRequest|WSGIRequest)" has no attribute'), + ], + 'many_to_many': [ + '(expression has type "List[Article]", variable has type "RelatedManager[Article]"', ], 'many_to_one': [ 'Incompatible type for "parent" of "Child" (got "None", expected "Union[Parent, Combinable]")', - 'Incompatible type for "parent" of "Child" (got "Child", expected "Union[Parent, Combinable]")' + 'Incompatible type for "parent" of "Child" (got "Child", expected "Union[Parent, Combinable]")', + 'expression has type "List[]", variable has type "RelatedManager[Article]"', + '"Reporter" has no attribute "cached_query"', ], 'middleware_exceptions': [ 'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any]"; expected "str"' @@ -209,9 +246,9 @@ IGNORED_ERRORS = { 'model_fields': [ 'Item "Field[Any, Any]" of "Union[Field[Any, Any], ForeignObjectRel]" has no attribute', 'Incompatible types in assignment (expression has type "Type[Person', - 'base class "IntegerFieldTests"', - 'ImageFieldTestMixin', 'Incompatible types in assignment (expression has type "FloatModel", variable has type', + 'No overload variant of "bytes" matches argument type "Container[int]"', + '"ImageFile" has no attribute "was_opened"', ], 'model_indexes': [ 'Argument "condition" to "Index" has incompatible type "str"; expected "Optional[Q]"' @@ -232,6 +269,12 @@ IGNORED_ERRORS = { '"PickledModel" has no attribute', '"Department" has no attribute "evaluate"', ], + 'model_formsets_regress': [ + 'Incompatible types in assignment (expression has type "int", target has type "str")', + ], + 'model_options': [ + 'expression has type "Dict[str, Type[Model]]", target has type "OrderedDict', + ], 'multiple_database': [ 'Unexpected attribute "extra_arg" for model "Book"' ], @@ -239,7 +282,6 @@ IGNORED_ERRORS = { "Cannot resolve keyword 'foo' into field" ], 'order_with_respect_to': [ - 'BaseOrderWithRespectToTests', '"Dimension" has no attribute "set_component_order"', ], 'one_to_one': [ @@ -255,8 +297,6 @@ IGNORED_ERRORS = { 'DummyJSONField', 'Incompatible types in assignment (expression has type "Type[Field[Any, Any]]', 'Argument "encoder" to "JSONField" has incompatible type "DjangoJSONEncoder";', - re.compile(r'Incompatible types in assignment \(expression has type "Type\[.+?\]", ' - r'base class "(UnaccentTest|TrigramTest)" defined the type as "Type\[CharFieldModel\]"\)'), '("None" and "SearchQuery")', ], 'properties': [ @@ -308,9 +348,9 @@ IGNORED_ERRORS = { 'List or tuple expected as variable arguments' ], 'sessions_tests': [ - 'base class "SessionTestsMixin" defined the type as "None")', 'Incompatible types in assignment (expression has type "None", variable has type "int")', - '"AbstractBaseSession" has no attribute' + '"AbstractBaseSession" has no attribute', + '"None" not callable', ], 'select_related': [ 'Item "ForeignKey[Union[Genus, Combinable], Genus]" ' @@ -324,18 +364,28 @@ IGNORED_ERRORS = { re.compile('Argument [0-9] to "WSGIRequestHandler"'), '"HTTPResponse" has no attribute', '"type" has no attribute', - '"WSGIRequest" has no attribute "makefile"' + '"WSGIRequest" has no attribute "makefile"', + 'LiveServerAddress', + '"Stub" has no attribute "makefile"', ], 'serializers': [ - '"SerializersTestBase" defined the type as "None"', '"Model" has no attribute "data"', '"Iterable[Any]" has no attribute "content"', + re.compile(r'Argument 1 to "(serialize|deserialize)" has incompatible type "None"; expected "str"') + ], + 'string_lookup': [ + '"Bar" has no attribute "place"', + ], + 'test_utils': [ + '"PossessedCar" has no attribute "color"', + 'expression has type "None", variable has type "List[str]"', ], 'transactions': [ 'Incompatible types in assignment (expression has type "Thread", variable has type "Callable[[], Any]")' ], 'urlpatterns': [ - '"object" not callable' + '"object" not callable', + '"None" not callable', ], 'urlpatterns_reverse': [ 'List or tuple expected as variable arguments', @@ -344,6 +394,7 @@ IGNORED_ERRORS = { ], 'utils_tests': [ 'Argument 1 to "activate" has incompatible type "None"; expected "Union[tzinfo, str]"', + 'Argument 1 to "activate" has incompatible type "Optional[str]"; expected "str"', 'Incompatible types in assignment (expression has type "None", base class "object" defined the type as', 'Class', 'has no attribute "cp"', @@ -351,11 +402,22 @@ IGNORED_ERRORS = { 'has no attribute "sort"', 'Unsupported target for indexed assignment', 'defined the type as "None"', - 'Argument 1 to "Path" has incompatible type "Optional[str]"' + 'Argument 1 to "Path" has incompatible type "Optional[str]"', + '"None" not callable', + '"WSGIRequest" has no attribute "process_response_content"', + 'No overload variant of "join" matches argument types "str", "None"', + 'Argument 1 to "Archive" has incompatible type "None"; expected "str"', + ], 'view_tests': [ - "Module 'django.views.debug' has no attribute 'Path'" - ] + "Module 'django.views.debug' has no attribute 'Path'", + 'Value of type "Optional[List[str]]" is not indexable', + 'ExceptionUser', + 'view_tests.tests.test_debug.User', + ], + 'validation': [ + 'has no attribute "name"', + ], } diff --git a/setup.py b/setup.py index 6524d47..e66da9a 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ with open('README.md', 'r') as f: readme = f.read() dependencies = [ - 'mypy>=0.730', + 'mypy>=0.740,<0.750', 'typing-extensions', 'django', ] diff --git a/test-data/typecheck/managers/querysets/test_filter.yml b/test-data/typecheck/managers/querysets/test_filter.yml index a084195..43056f5 100644 --- a/test-data/typecheck/managers/querysets/test_filter.yml +++ b/test-data/typecheck/managers/querysets/test_filter.yml @@ -33,7 +33,7 @@ - case: filter_with_invalid_type main: | from myapp.models import User - User.objects.filter(age='hello') # E: Incompatible type for lookup 'age': (got "str", expected "int") + User.objects.filter(age=User()) # E: Incompatible type for lookup 'age': (got "User", expected "Union[str, int]") installed_apps: - myapp files: @@ -49,12 +49,12 @@ - case: filter_with_multiple_fields main: | from myapp.models import User - User.objects.filter(age='hello', gender='world') + User.objects.filter(age=User(), gender=User()) installed_apps: - myapp out: | - main:2: error: Incompatible type for lookup 'age': (got "str", expected "int") - main:2: error: Incompatible type for lookup 'gender': (got "str", expected "int") + main:2: error: Incompatible type for lookup 'age': (got "User", expected "Union[str, int]") + main:2: error: Incompatible type for lookup 'gender': (got "User", expected "Union[str, int]") files: - path: myapp/__init__.py - path: myapp/models.py @@ -128,7 +128,7 @@ Blog.objects.filter(publisher__id=1) Blog.objects.filter(publisher=blog) # E: Incompatible type for lookup 'publisher': (got "Blog", expected "Union[Publisher, int, None]") - Blog.objects.filter(publisher_id='hello') # E: Incompatible type for lookup 'publisher_id': (got "str", expected "int") + Blog.objects.filter(publisher_id=blog) # E: Incompatible type for lookup 'publisher_id': (got "Blog", expected "Union[str, int]") installed_apps: - myapp files: @@ -151,7 +151,7 @@ Publisher.objects.filter(blogs__id=1) Publisher.objects.filter(blogs=publisher) # E: Incompatible type for lookup 'blogs': (got "Publisher", expected "Union[Blog, int, None]") - Publisher.objects.filter(blogs__id=publisher) # E: Incompatible type for lookup 'blogs__id': (got "Publisher", expected "int") + Publisher.objects.filter(blogs__id=publisher) # E: Incompatible type for lookup 'blogs__id': (got "Publisher", expected "Union[str, int]") installed_apps: - myapp files: @@ -253,4 +253,4 @@ class User(models.Model): username = models.TextField() username2 = models.TextField() - age = models.IntegerField() + age = models.IntegerField() \ No newline at end of file