From b1153204d712b3bc351d94e5e441c568a9936ea6 Mon Sep 17 00:00:00 2001 From: Maxim Kurnikov Date: Wed, 30 Jan 2019 21:01:33 +0300 Subject: [PATCH] enable bunch of folders --- django-stubs/contrib/contenttypes/fields.pyi | 3 +- .../humanize/templatetags/humanize.pyi | 2 +- django-stubs/contrib/messages/__init__.pyi | 1 + django-stubs/core/handlers/base.pyi | 4 + django-stubs/db/__init__.pyi | 3 +- django-stubs/db/models/__init__.pyi | 2 + django-stubs/db/models/base.pyi | 7 ++ django-stubs/db/models/deletion.pyi | 4 + django-stubs/db/models/fields/__init__.pyi | 46 +++++++++- django-stubs/db/models/fields/files.pyi | 2 - django-stubs/db/models/fields/related.pyi | 64 +++++++++++++- django-stubs/db/models/query.pyi | 28 ++++-- django-stubs/db/models/sql/__init__.pyi | 7 ++ django-stubs/db/models/sql/query.pyi | 6 +- django-stubs/db/models/sql/subqueries.pyi | 42 ++++----- django-stubs/forms/__init__.pyi | 38 ++++++++ django-stubs/forms/formsets.pyi | 10 +++ django-stubs/forms/models.pyi | 47 +++++----- django-stubs/http/request.pyi | 1 + django-stubs/http/response.pyi | 2 +- django-stubs/shortcuts.pyi | 7 +- scripts/typecheck_tests.py | 87 ++++++++++++++++++- 22 files changed, 338 insertions(+), 75 deletions(-) diff --git a/django-stubs/contrib/contenttypes/fields.pyi b/django-stubs/contrib/contenttypes/fields.pyi index ba3a163..c5e7582 100644 --- a/django-stubs/contrib/contenttypes/fields.pyi +++ b/django-stubs/contrib/contenttypes/fields.pyi @@ -79,6 +79,7 @@ class GenericRelation(ForeignObject): object_id_field_name: Any = ... content_type_field_name: Any = ... for_concrete_model: Any = ... + to_fields: Any = ... def __init__( self, to: Union[Type[Model], str], @@ -90,13 +91,11 @@ class GenericRelation(ForeignObject): **kwargs: Any ) -> None: ... def check(self, **kwargs: Any) -> List[Error]: ... - to_fields: Any = ... def resolve_related_fields(self) -> List[Tuple[PositiveIntegerField, Field]]: ... def get_path_info(self, filtered_relation: Optional[FilteredRelation] = ...) -> List[PathInfo]: ... def get_reverse_path_info(self, filtered_relation: None = ...) -> List[PathInfo]: ... def value_to_string(self, obj: Model) -> str: ... model: Any = ... - def contribute_to_class(self, cls: Type[Model], name: str, **kwargs: Any) -> None: ... def set_attributes_from_rel(self) -> None: ... def get_internal_type(self) -> str: ... def get_content_type(self) -> ContentType: ... diff --git a/django-stubs/contrib/humanize/templatetags/humanize.pyi b/django-stubs/contrib/humanize/templatetags/humanize.pyi index d4e2f8d..86e7459 100644 --- a/django-stubs/contrib/humanize/templatetags/humanize.pyi +++ b/django-stubs/contrib/humanize/templatetags/humanize.pyi @@ -1,4 +1,4 @@ -from datetime import date, datetime +from datetime import date, datetime as datetime from decimal import Decimal from typing import Any, Optional, Union diff --git a/django-stubs/contrib/messages/__init__.pyi b/django-stubs/contrib/messages/__init__.pyi index e69de29..6386c11 100644 --- a/django-stubs/contrib/messages/__init__.pyi +++ b/django-stubs/contrib/messages/__init__.pyi @@ -0,0 +1 @@ +from .api import get_level as get_level, set_level as set_level diff --git a/django-stubs/core/handlers/base.pyi b/django-stubs/core/handlers/base.pyi index c15523a..03b89fe 100644 --- a/django-stubs/core/handlers/base.pyi +++ b/django-stubs/core/handlers/base.pyi @@ -6,6 +6,10 @@ from django.http.response import HttpResponse, HttpResponseBase logger: Any class BaseHandler: + _view_middleware: None = ... + _template_response_middleware: None = ... + _exception_middleware: None = ... + _middleware_chain: None = ... def load_middleware(self) -> None: ... def make_view_atomic(self, view: Callable) -> Callable: ... def get_exception_response(self, request: Any, resolver: Any, status_code: Any, exception: Any): ... diff --git a/django-stubs/db/__init__.pyi b/django-stubs/db/__init__.pyi index 5115442..3e5bec8 100644 --- a/django-stubs/db/__init__.pyi +++ b/django-stubs/db/__init__.pyi @@ -18,10 +18,11 @@ from . import migrations connections: Any router: Any +connection: Any class DefaultConnectionProxy: def __getattr__(self, item: str) -> Any: ... def __setattr__(self, name: str, value: Any) -> None: ... def __delattr__(self, name: str) -> None: ... -connection: Any +def close_old_connections(**kwargs): ... diff --git a/django-stubs/db/models/__init__.pyi b/django-stubs/db/models/__init__.pyi index df8b5aa..371a114 100644 --- a/django-stubs/db/models/__init__.pyi +++ b/django-stubs/db/models/__init__.pyi @@ -80,3 +80,5 @@ from .aggregates import ( Sum as Sum, Aggregate as Aggregate, ) + +from .indexes import Index as Index diff --git a/django-stubs/db/models/base.pyi b/django-stubs/db/models/base.pyi index 1a64205..c7c88cf 100644 --- a/django-stubs/db/models/base.pyi +++ b/django-stubs/db/models/base.pyi @@ -23,3 +23,10 @@ class Model(metaclass=ModelBase): ) -> None: ... def refresh_from_db(self, using: None = ..., fields: Optional[List[str]] = ...) -> None: ... def get_deferred_fields(self) -> Set[str]: ... + +class ModelStateFieldsCacheDescriptor: ... + +class ModelState: + db: None = ... + adding: bool = ... + fields_cache: ModelStateFieldsCacheDescriptor = ... diff --git a/django-stubs/db/models/deletion.pyi b/django-stubs/db/models/deletion.pyi index 96fed2c..10f78ef 100644 --- a/django-stubs/db/models/deletion.pyi +++ b/django-stubs/db/models/deletion.pyi @@ -1,5 +1,9 @@ +from django.db import IntegrityError + def CASCADE(collector, field, sub_objs, using): ... def SET_NULL(collector, field, sub_objs, using): ... def SET_DEFAULT(collector, field, sub_objs, using): ... def DO_NOTHING(collector, field, sub_objs, using): ... def PROTECT(collector, field, sub_objs, using): ... + +class ProtectedError(IntegrityError): ... diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index 8c4ab91..d2629c6 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -1,8 +1,8 @@ -from typing import Any, Optional, Tuple, Iterable, Callable, Dict, Union +from typing import Any, Optional, Tuple, Iterable, Callable, Dict, Union, Type +from django.db.models import Model from django.db.models.query_utils import RegisterLookupMixin - -from django.forms.widgets import Widget +from django.forms import Widget, Field as FormField _Choice = Tuple[Any, str] _ChoiceNamedGroup = Tuple[str, Iterable[_Choice]] @@ -15,11 +15,13 @@ class Field(RegisterLookupMixin): widget: Widget help_text: str db_table: str + remote_field: Field def __init__( self, verbose_name: Optional[str] = ..., name: Optional[str] = ..., primary_key: bool = ..., + max_length: Optional[int] = ..., unique: bool = ..., blank: bool = ..., null: bool = ..., @@ -36,6 +38,12 @@ class Field(RegisterLookupMixin): error_messages: Optional[_ErrorMessagesToOverride] = ..., ): ... def __get__(self, instance, owner) -> Any: ... + def deconstruct(self) -> Any: ... + def set_attributes_from_name(self, name: str) -> None: ... + def db_parameters(self, connection: Any) -> Dict[str, str]: ... + def get_prep_value(self, value: Any) -> Any: ... + def formfield(self, **kwargs) -> FormField: ... + def contribute_to_class(self, cls: Type[Model], name: str, private_only: bool = ...) -> None: ... class IntegerField(Field): def __get__(self, instance, owner) -> int: ... @@ -91,6 +99,9 @@ class CharField(Field): editable: bool = ..., auto_created: bool = ..., serialize: bool = ..., + unique_for_date: Optional[str] = ..., + unique_for_month: Optional[str] = ..., + unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., help_text: str = ..., db_column: Optional[str] = ..., @@ -117,6 +128,9 @@ class SlugField(CharField): editable: bool = ..., auto_created: bool = ..., serialize: bool = ..., + unique_for_date: Optional[str] = ..., + unique_for_month: Optional[str] = ..., + unique_for_year: Optional[str] = ..., choices: Optional[_FieldChoices] = ..., help_text: str = ..., db_column: Optional[str] = ..., @@ -196,7 +210,30 @@ class DateField(DateTimeCheckMixin, Field): error_messages: Optional[_ErrorMessagesToOverride] = ..., ): ... -class TimeField(DateTimeCheckMixin, Field): ... +class TimeField(DateTimeCheckMixin, Field): + def __init__( + self, + verbose_name: Optional[str] = ..., + name: Optional[str] = ..., + auto_now: bool = ..., + auto_now_add: bool = ..., + primary_key: bool = ..., + unique: bool = ..., + blank: bool = ..., + null: bool = ..., + db_index: bool = ..., + default: Any = ..., + editable: bool = ..., + auto_created: bool = ..., + serialize: bool = ..., + choices: Optional[_FieldChoices] = ..., + help_text: str = ..., + db_column: Optional[str] = ..., + db_tablespace: Optional[str] = ..., + validators: Iterable[_ValidatorCallable] = ..., + error_messages: Optional[_ErrorMessagesToOverride] = ..., + ): ... + class DateTimeField(DateField): ... class UUIDField(Field): ... @@ -211,6 +248,7 @@ class FilePathField(Field): allow_files: bool = ..., allow_folders: bool = ..., primary_key: bool = ..., + max_length: int = ..., unique: bool = ..., blank: bool = ..., null: bool = ..., diff --git a/django-stubs/db/models/fields/files.pyi b/django-stubs/db/models/fields/files.pyi index c6c7ee9..bb53d59 100644 --- a/django-stubs/db/models/fields/files.pyi +++ b/django-stubs/db/models/fields/files.pyi @@ -51,7 +51,6 @@ class FileField(Field): def get_internal_type(self) -> str: ... def get_prep_value(self, value: Union[FieldFile, str]) -> str: ... def pre_save(self, model_instance: Model, add: bool) -> FieldFile: ... - def contribute_to_class(self, cls: Type[Model], name: str, **kwargs: Any) -> None: ... def generate_filename(self, instance: Optional[Model], filename: str) -> str: ... def save_form_data(self, instance: Model, data: Optional[Union[bool, File, str]]) -> None: ... def formfield(self, **kwargs: Any) -> form_fields.FileField: ... @@ -75,6 +74,5 @@ class ImageField(FileField): ) -> None: ... def check(self, **kwargs: Any) -> List[Any]: ... def deconstruct(self) -> Any: ... - def contribute_to_class(self, cls: Type[Model], name: str, **kwargs: Any) -> None: ... def update_dimension_fields(self, instance: Model, force: bool = ..., *args: Any, **kwargs: Any) -> None: ... def formfield(self, **kwargs: Any) -> form_fields.ImageField: ... diff --git a/django-stubs/db/models/fields/related.pyi b/django-stubs/db/models/fields/related.pyi index 5cf5efa..aa5c703 100644 --- a/django-stubs/db/models/fields/related.pyi +++ b/django-stubs/db/models/fields/related.pyi @@ -1,9 +1,30 @@ -from typing import Type, Union, TypeVar, Any, Generic, List, Optional, Dict, Callable, Tuple, Sequence, TYPE_CHECKING +from typing import ( + Type, + Union, + TypeVar, + Any, + Generic, + List, + Optional, + Dict, + Callable, + Tuple, + Sequence, + TYPE_CHECKING, + Iterable, +) from uuid import UUID from django.db import models from django.db.models import Field, Model, QuerySet from django.db.models.fields.mixins import FieldCacheMixin +from django.db.models.fields.related_descriptors import ( + ReverseManyToOneDescriptor as ReverseManyToOneDescriptor, + ReverseOneToOneDescriptor as ReverseOneToOneDescriptor, + ForwardManyToOneDescriptor as ForwardManyToOneDescriptor, + ForwardOneToOneDescriptor as ForwardOneToOneDescriptor, +) +from django.db.models.fields.reverse_related import ForeignObjectRel as ForeignObjectRel from django.db.models.query_utils import PathInfo, Q if TYPE_CHECKING: @@ -11,6 +32,13 @@ if TYPE_CHECKING: _T = TypeVar("_T", bound=models.Model) +_Choice = Tuple[Any, str] +_ChoiceNamedGroup = Tuple[str, Iterable[_Choice]] +_FieldChoices = Iterable[Union[_Choice, _ChoiceNamedGroup]] + +_ValidatorCallable = Callable[..., None] +_ErrorMessagesToOverride = Dict[str, Any] + class RelatedField(FieldCacheMixin, Field): one_to_many: bool = ... one_to_one: bool = ... @@ -29,12 +57,41 @@ class RelatedField(FieldCacheMixin, Field): def set_attributes_from_rel(self) -> None: ... def do_related_class(self, other: Type[Model], cls: Type[Model]) -> None: ... def get_limit_choices_to(self) -> Dict[str, int]: ... - def formfield(self, **kwargs: Any) -> Field: ... def related_query_name(self) -> str: ... @property def target_field(self) -> Field: ... -class ForeignObject(RelatedField): ... +class ForeignObject(RelatedField): + def __init__( + self, + to: Union[Type[Model], str], + on_delete: Callable[..., None], + from_fields: Sequence[str], + to_fields: Sequence[str], + rel: None = ..., + related_name: Optional[str] = ..., + related_query_name: None = ..., + limit_choices_to: None = ..., + parent_link: bool = ..., + swappable: bool = ..., + verbose_name: Optional[str] = ..., + name: Optional[str] = ..., + primary_key: bool = ..., + unique: bool = ..., + blank: bool = ..., + null: bool = ..., + db_index: bool = ..., + default: Any = ..., + editable: bool = ..., + auto_created: bool = ..., + serialize: bool = ..., + choices: Optional[_FieldChoices] = ..., + help_text: str = ..., + db_column: Optional[str] = ..., + db_tablespace: Optional[str] = ..., + validators: Iterable[_ValidatorCallable] = ..., + error_messages: Optional[_ErrorMessagesToOverride] = ..., + ): ... class ForeignKey(RelatedField, Generic[_T]): def __init__(self, to: Union[Type[_T], str], on_delete: Any, related_name: str = ..., **kwargs): ... @@ -80,7 +137,6 @@ class ManyToManyField(RelatedField, Generic[_T]): m2m_reverse_field_name: Any = ... m2m_target_field_name: Any = ... m2m_reverse_target_field_name: Any = ... - def contribute_to_class(self, cls: Type[Model], name: str, **kwargs) -> None: ... def contribute_to_related_class(self, cls: Type[Model], related: RelatedField) -> None: ... def set_attributes_from_rel(self) -> None: ... def value_from_object(self, obj: Model) -> List[Model]: ... diff --git a/django-stubs/db/models/query.pyi b/django-stubs/db/models/query.pyi index cfa1721..5efdebb 100644 --- a/django-stubs/db/models/query.pyi +++ b/django-stubs/db/models/query.pyi @@ -1,12 +1,26 @@ -from typing import TypeVar, Optional, Any, Type, Dict, Union, overload, List, Iterator, Tuple, Iterable, Sized, Sequence +from typing import ( + Any, + Dict, + Iterable, + Iterator, + List, + MutableMapping, + Optional, + Sequence, + Sized, + Tuple, + Type, + TypeVar, + Union, + overload, +) from django.db.models.base import Model +from django.db.models.expressions import Combinable +from django.db.models.sql.query import Query, RawQuery from django.db import models from django.db.models import Manager -from django.db.models.sql.query import Query, RawQuery - -from django.db.models.expressions import F, Combinable _T = TypeVar("_T", bound=models.Model, covariant=True) @@ -38,8 +52,10 @@ class QuerySet(Iterable[_T], Sized): def get(self, *args: Any, **kwargs: Any) -> _T: ... def create(self, **kwargs: Any) -> _T: ... def bulk_create(self, objs: Iterable[Model], batch_size: Optional[int] = ...) -> List[_T]: ... - def get_or_create(self, defaults: Optional[Dict[str, Any]] = ..., **kwargs: Any) -> Tuple[_T, bool]: ... - def update_or_create(self, defaults: Optional[Dict[str, Any]] = ..., **kwargs: Any) -> Tuple[_T, bool]: ... + def get_or_create(self, defaults: Optional[MutableMapping[str, Any]] = ..., **kwargs: Any) -> Tuple[_T, bool]: ... + def update_or_create( + self, defaults: Optional[MutableMapping[str, Any]] = ..., **kwargs: Any + ) -> Tuple[_T, bool]: ... def earliest(self, *fields: Any, field_name: Optional[Any] = ...) -> _T: ... def latest(self, *fields: Any, field_name: Optional[Any] = ...) -> _T: ... def first(self) -> Optional[_T]: ... diff --git a/django-stubs/db/models/sql/__init__.pyi b/django-stubs/db/models/sql/__init__.pyi index 6797523..f5fadda 100644 --- a/django-stubs/db/models/sql/__init__.pyi +++ b/django-stubs/db/models/sql/__init__.pyi @@ -1 +1,8 @@ from .query import Query as Query, RawQuery as RawQuery + +from .subqueries import ( + InsertQuery as InsertQuery, + AggregateQuery as AggregateQuery, + DeleteQuery as DeleteQuery, + UpdateQuery as UpdateQuery, +) diff --git a/django-stubs/db/models/sql/query.pyi b/django-stubs/db/models/sql/query.pyi index bfee104..6364b43 100644 --- a/django-stubs/db/models/sql/query.pyi +++ b/django-stubs/db/models/sql/query.pyi @@ -5,6 +5,8 @@ from decimal import Decimal from typing import Any, Callable, Dict, Iterator, List, Optional, Set, Tuple, Type, Union from uuid import UUID +from django.db.models.sql.datastructures import BaseTable + from django.db.models import Model, Field, Q, FilteredRelation, Expression, QuerySet from django.db.models.query_utils import PathInfo from django.db.models.sql.compiler import SQLCompiler @@ -28,7 +30,7 @@ class RawQuery: class Query: base_table: str - related_ids: None + related_ids: Optional[List[int]] related_updates: Dict[Type[Model], List[Tuple[Field, None, Union[int, str]]]] values: List[Any] alias_prefix: str = ... @@ -36,7 +38,7 @@ class Query: compiler: str = ... model: Optional[Type[Model]] = ... alias_refcount: Dict[str, int] = ... - alias_map: OrderedDict = ... + alias_map: Dict[str, BaseTable] = ... external_aliases: Set[str] = ... table_map: Dict[str, List[str]] = ... default_cols: bool = ... diff --git a/django-stubs/db/models/sql/subqueries.pyi b/django-stubs/db/models/sql/subqueries.pyi index 5d7c237..35f2b0a 100644 --- a/django-stubs/db/models/sql/subqueries.pyi +++ b/django-stubs/db/models/sql/subqueries.pyi @@ -1,12 +1,15 @@ -from typing import Any, Dict, List, Optional, Tuple, Type, Union +import collections +import uuid +from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Type, Union from django.db.models.base import Model from django.db.models.expressions import Case -from django.db.models.fields import DateTimeCheckMixin, Field from django.db.models.query import QuerySet +from django.db.models.sql.datastructures import BaseTable from django.db.models.sql.query import Query from django.db.models.sql.where import WhereNode -from django.utils.datastructures import ImmutableList + +from django.db.models.fields import Field class DeleteQuery(Query): alias_refcount: Dict[str, int] @@ -46,16 +49,14 @@ class DeleteQuery(Query): table_map: Dict[str, List[str]] used_aliases: Set[str] values_select: Tuple - where_class: Type[django.db.models.sql.where.WhereNode] + where_class: Type[WhereNode] compiler: str = ... - alias_map: Union[Dict[str, django.db.models.sql.datastructures.BaseTable], collections.OrderedDict] = ... - where: django.db.models.sql.where.WhereNode = ... + where: WhereNode = ... def do_query(self, table: str, where: WhereNode, using: str) -> int: ... def delete_batch(self, pk_list: Union[List[int], List[str]], using: str) -> int: ... def delete_qs(self, query: QuerySet, using: str) -> int: ... class UpdateQuery(Query): - alias_map: collections.OrderedDict alias_refcount: Dict[str, int] annotation_select_mask: Optional[Set[Any]] base_table: str @@ -81,8 +82,6 @@ class UpdateQuery(Query): max_depth: int model: Type[Model] order_by: Tuple - related_ids: Optional[List[int]] - related_updates: Dict[Type[Model], List[Tuple[Field, None, Union[int, str]]]] select: Tuple select_for_update: bool select_for_update_nowait: bool @@ -94,13 +93,13 @@ class UpdateQuery(Query): subquery: bool table_map: Dict[str, List[str]] used_aliases: Set[str] - values: List[Tuple[Field, Optional[Type[Model]], Union[django.db.models.expressions.Case, uuid.UUID]]] + values: List[Tuple[Field, Optional[Type[Model]], Union[Case, uuid.UUID]]] values_select: Tuple - where_class: Type[django.db.models.sql.where.WhereNode] + where_class: Type[WhereNode] compiler: str = ... def __init__(self, *args: Any, **kwargs: Any) -> None: ... def clone(self) -> UpdateQuery: ... - where: django.db.models.sql.where.WhereNode = ... + where: WhereNode = ... def update_batch(self, pk_list: List[int], values: Dict[str, Optional[int]], using: str) -> None: ... def add_update_values(self, values: Dict[str, Any]) -> None: ... def add_update_fields(self, values_seq: List[Tuple[Field, Optional[Type[Model]], Case]]) -> None: ... @@ -108,7 +107,6 @@ class UpdateQuery(Query): def get_related_updates(self) -> List[UpdateQuery]: ... class InsertQuery(Query): - alias_map: collections.OrderedDict alias_refcount: Dict[str, int] annotation_select_mask: None combinator: None @@ -144,21 +142,16 @@ class InsertQuery(Query): table_map: Dict[str, List[str]] used_aliases: Set[Any] values_select: Tuple - where: django.db.models.sql.where.WhereNode - where_class: Type[django.db.models.sql.where.WhereNode] + where: WhereNode + where_class: Type[WhereNode] compiler: str = ... - fields: Union[ - List[django.db.models.fields.DateTimeCheckMixin], List[Field], django.utils.datastructures.ImmutableList - ] = ... + fields: Iterable[Field] = ... objs: List[Model] = ... def __init__(self, *args: Any, **kwargs: Any) -> None: ... raw: bool = ... - def insert_values( - self, fields: Union[List[DateTimeCheckMixin], List[Field], ImmutableList], objs: List[Model], raw: bool = ... - ) -> None: ... + def insert_values(self, fields: Iterable[Field], objs: List[Model], raw: bool = ...) -> None: ... class AggregateQuery(Query): - alias_map: collections.OrderedDict alias_refcount: Dict[Any, Any] annotation_select_mask: None combinator: None @@ -191,11 +184,10 @@ class AggregateQuery(Query): select_related: bool standard_ordering: bool sub_params: Tuple - subquery: Union[bool, str] table_map: Dict[Any, Any] used_aliases: Set[Any] values_select: Tuple - where: django.db.models.sql.where.WhereNode - where_class: Type[django.db.models.sql.where.WhereNode] + where: WhereNode + where_class: Type[WhereNode] compiler: str = ... def add_subquery(self, query: Query, using: str) -> None: ... diff --git a/django-stubs/forms/__init__.pyi b/django-stubs/forms/__init__.pyi index a24c1ad..a476594 100644 --- a/django-stubs/forms/__init__.pyi +++ b/django-stubs/forms/__init__.pyi @@ -15,6 +15,25 @@ from .widgets import ( Select as Select, CheckboxInput as CheckboxInput, CheckboxSelectMultiple as CheckboxSelectMultiple, + Media as Media, + MultiWidget as MultiWidget, + TextInput as TextInput, + Textarea as Textarea, + Input as Input, + ClearableFileInput as ClearableFileInput, + DateInput as DateInput, + DateTimeBaseInput as DateTimeBaseInput, + DateTimeInput as DateTimeInput, + EmailInput as EmailInput, + FileInput as FileInput, + HiddenInput as HiddenInput, + MultipleHiddenInput as MultipleHiddenInput, + NullBooleanSelect as NullBooleanSelect, + PasswordInput as PasswordInput, + RadioSelect as RadioSelect, + SelectMultiple as SelectMultiple, + TimeInput as TimeInput, + URLInput as URLInput, ) from .fields import ( @@ -26,4 +45,23 @@ from .fields import ( ImageField as ImageField, DateTimeField as DateTimeField, DateField as DateField, + BooleanField as BooleanField, + EmailField as EmailField, + FloatField as FloatField, + MultiValueField as MultiValueField, + MultipleChoiceField as MultipleChoiceField, + NullBooleanField as NullBooleanField, + SplitDateTimeField as SplitDateTimeField, + TimeField as TimeField, + IntegerField as IntegerField, + FilePathField as FilePathField, + DecimalField as DecimalField, + UUIDField as UUIDField, + URLField as URLField, + ComboField as ComboField, + GenericIPAddressField as GenericIPAddressField, + RegexField as RegexField, + SlugField as SlugField, + TypedChoiceField as TypedChoiceField, + TypedMultipleChoiceField as TypedMultipleChoiceField, ) diff --git a/django-stubs/forms/formsets.pyi b/django-stubs/forms/formsets.pyi index 89ed16a..3a0e4ee 100644 --- a/django-stubs/forms/formsets.pyi +++ b/django-stubs/forms/formsets.pyi @@ -6,6 +6,16 @@ from django.forms.utils import ErrorList from django.forms import Form +TOTAL_FORM_COUNT: str = ... +INITIAL_FORM_COUNT: str = ... +MIN_NUM_FORM_COUNT: str = ... +MAX_NUM_FORM_COUNT: str = ... +ORDERING_FIELD_NAME: str = ... +DELETION_FIELD_NAME: str = ... + +DEFAULT_MIN_NUM: int = ... +DEFAULT_MAX_NUM: int = ... + class ManagementForm(Form): auto_id: Union[bool, str] cleaned_data: Dict[str, Optional[int]] diff --git a/django-stubs/forms/models.pyi b/django-stubs/forms/models.pyi index 6d79a5b..d9558fa 100644 --- a/django-stubs/forms/models.pyi +++ b/django-stubs/forms/models.pyi @@ -1,10 +1,11 @@ from collections import OrderedDict from datetime import date, datetime -from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple, Type, Union +from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple, Type, Union, Sequence from unittest.mock import MagicMock from uuid import UUID from django.core.files.uploadedfile import SimpleUploadedFile +from django.db.models import ForeignKey from django.db.models.base import Model from django.db.models.manager import Manager from django.db.models.query import QuerySet @@ -136,23 +137,23 @@ class BaseModelFormSet(BaseFormSet): def modelformset_factory( model: Type[Model], form: Type[ModelForm] = ..., - formfield_callback: None = ..., + formfield_callback: Optional[Callable] = ..., formset: Type[BaseModelFormSet] = ..., extra: int = ..., can_delete: bool = ..., can_order: bool = ..., - max_num: None = ..., - fields: None = ..., - exclude: None = ..., - widgets: None = ..., + min_num: Optional[int] = ..., + max_num: Optional[int] = ..., + fields: Optional[Union[str, Sequence[str]]] = ..., + exclude: Optional[Sequence[str]] = ..., + widgets: Optional[Dict[str, Any]] = ..., validate_max: bool = ..., localized_fields: None = ..., - labels: None = ..., - help_texts: None = ..., - error_messages: None = ..., - min_num: None = ..., + labels: Optional[Dict[str, str]] = ..., + help_texts: Optional[Dict[str, str]] = ..., + error_messages: Optional[Dict[str, Dict[str, str]]] = ..., validate_min: bool = ..., - field_classes: None = ..., + field_classes: Optional[Dict[str, Any]] = ..., ) -> Any: ... class BaseInlineFormSet(BaseModelFormSet): @@ -182,22 +183,22 @@ def inlineformset_factory( form: Type[ModelForm] = ..., formset: Type[BaseInlineFormSet] = ..., fk_name: Optional[str] = ..., - fields: Optional[str] = ..., - exclude: None = ..., + fields: Optional[Union[str, Sequence[str]]] = ..., + exclude: Optional[Sequence[str]] = ..., extra: int = ..., can_order: bool = ..., can_delete: bool = ..., - max_num: None = ..., - formfield_callback: None = ..., - widgets: None = ..., + max_num: Optional[int] = ..., + formfield_callback: Optional[Callable] = ..., + widgets: Optional[Dict[str, Any]] = ..., validate_max: bool = ..., localized_fields: None = ..., - labels: None = ..., - help_texts: None = ..., - error_messages: None = ..., - min_num: None = ..., + labels: Optional[Dict[str, str]] = ..., + help_texts: Optional[Dict[str, str]] = ..., + error_messages: Optional[Dict[str, Dict[str, str]]] = ..., + min_num: Optional[int] = ..., validate_min: bool = ..., - field_classes: None = ..., + field_classes: Optional[Dict[str, Any]] = ..., ) -> Any: ... class InlineForeignKeyField(Field): @@ -266,3 +267,7 @@ class ModelMultipleChoiceField(ModelChoiceField): hidden_widget: Any = ... default_error_messages: Any = ... def __init__(self, queryset: QuerySet, **kwargs: Any) -> None: ... + +def _get_foreign_key( + parent_model: Type[Model], model: Type[Model], fk_name: Optional[str] = ..., can_fail: bool = ... +) -> ForeignKey: ... diff --git a/django-stubs/http/request.pyi b/django-stubs/http/request.pyi index 6bb93ec..7b2c668 100644 --- a/django-stubs/http/request.pyi +++ b/django-stubs/http/request.pyi @@ -60,6 +60,7 @@ class HttpRequest(BytesIO): class QueryDict(MultiValueDict[str, str]): encoding = str # type: Any + _mutable: bool = ... def __init__( self, query_string: Union[str, bytes, None] = None, mutable: bool = False, encoding: Optional[str] = None ) -> None: ... diff --git a/django-stubs/http/response.pyi b/django-stubs/http/response.pyi index 41d0cc9..776e40d 100644 --- a/django-stubs/http/response.pyi +++ b/django-stubs/http/response.pyi @@ -31,7 +31,7 @@ class HttpResponseBase(six.Iterator): def has_header(self, header: str) -> bool: ... def items(self) -> Iterable[Tuple[str, str]]: ... @overload - def get(self, header: str, alternate: str = ...) -> str: ... + def get(self, header: str, alternate: str) -> str: ... @overload def get(self, header: str) -> Optional[str]: ... def set_cookie( diff --git a/django-stubs/shortcuts.pyi b/django-stubs/shortcuts.pyi index fc1b900..05ab839 100644 --- a/django-stubs/shortcuts.pyi +++ b/django-stubs/shortcuts.pyi @@ -1,6 +1,7 @@ from typing import Any, Callable, Dict, List, Optional, Type, Union -from django.db.models.base import Model, Manager, QuerySet +from django.db.models import Manager, QuerySet +from django.db.models.base import Model from django.http.response import HttpResponse, HttpResponseRedirect from django.http import HttpRequest @@ -21,6 +22,6 @@ def render( using: Optional[str] = ..., ) -> HttpResponse: ... def redirect(to: Union[Callable, str], *args: Any, permanent: bool = ..., **kwargs: Any) -> HttpResponseRedirect: ... -def get_object_or_404(klass: Union[Type[Model], Type[Manager], QuerySet], *args: Any, **kwargs: Any) -> Model: ... -def get_list_or_404(klass: List[Type[Model]], *args: Any, **kwargs: Any) -> List[Model]: ... +def get_object_or_404(klass: Union[Type[Model], Manager, QuerySet], *args: Any, **kwargs: Any) -> Model: ... +def get_list_or_404(klass: Union[Type[Model], Manager, QuerySet], *args: Any, **kwargs: Any) -> List[Model]: ... def resolve_url(to: Union[Callable, Model, str], *args: Any, **kwargs: Any) -> str: ... diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 26ffb9f..304b587 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -44,6 +44,10 @@ IGNORED_ERROR_PATTERNS = [ 'expression has type "property"', '"object" has no attribute "__iter__"', 'Too few arguments for "dates" of "QuerySet"', + 'has no attribute "vendor"', + 'Argument 1 to "get_list_or_404" has incompatible type "List', + 'error: "AdminRadioSelect" has no attribute "can_add_related"', + re.compile('Cannot determine type of \'(objects|stuff|specimens)\''), re.compile(r'"Callable\[\[(Any(, )?)+\], Any\]" has no attribute'), re.compile(r'"HttpResponseBase" has no attribute "[A-Za-z_]+"'), re.compile(r'Incompatible types in assignment \(expression has type "Tuple\[\]", ' @@ -52,9 +56,12 @@ IGNORED_ERROR_PATTERNS = [ re.compile(r'Module has no attribute "[A-Za-z_]+"'), re.compile(r'"[A-Za-z\[\]]+" has no attribute "getvalue"'), # TODO: remove when reassignment will be possible (in 0.670? ) - re.compile(r'Incompatible types in assignment \(expression has type "(QuerySet|List){1}\[[A-Za-z, ]+\]", ' - r'variable has type "(QuerySet|List){1}\[[A-Za-z, ]+\]"\)'), + re.compile(r'Incompatible types in assignment \(expression has type "(QuerySet|List)\[[A-Za-z, ]+\]", ' + r'variable has type "(QuerySet|List)\[[A-Za-z, ]+\]"\)'), re.compile(r'"(MockRequest|DummyRequest|DummyUser)" has no attribute "[a-zA-Z_]+"'), + # TODO: remove when form <-> model plugin support is added + re.compile(r'"Model" has no attribute "[A-Za-z_]+"'), + re.compile(r'Argument 1 to "get_object_or_404" has incompatible type "(str|Type\[CustomClass\])"'), ] # Test folders to typecheck @@ -116,7 +123,81 @@ TESTS_DIRS = [ 'empty', # TODO: 'expressions', 'expressions_case', - # TODO: 'expressions_window' + # TODO: 'expressions_window', + # TODO: 'extra_regress', + # TODO: 'field_deconstruction', + 'field_defaults', + 'field_subclassing', + # TODO: 'file_storage', + # TODO: 'file_uploads', + # TODO: 'files', + 'filtered_relation', + # TODO: 'fixtures', + 'fixtures_model_package', + # TODO: 'fixtures_regress', + 'flatpages_tests', + 'force_insert_update', + 'foreign_object', + # TODO: 'forms_tests', + 'from_db_value', + # TODO: 'generic_inline_admin', + # TODO: 'generic_relations', + 'generic_relations_regress', + # TODO: 'generic_views', + 'get_earliest_or_latest', + 'get_object_or_404', + # TODO: 'get_or_create', + # TODO: 'gis_tests', + 'handlers', + # TODO: 'httpwrappers', + 'humanize_tests', + # TODO: 'i18n', + 'import_error_package', + 'indexes', + 'inline_formsets', + 'inspectdb', + 'introspection', + # TODO: 'invalid_models_tests', + 'known_related_objects', + # TODO: 'logging_tests', + # TODO: 'lookup', + 'm2m_and_m2o', + 'm2m_intermediary', + 'm2m_multiple', + 'm2m_recursive', + 'm2m_regress', + 'm2m_signals', + 'm2m_through', + 'm2m_through_regress', + 'm2o_recursive', + # TODO: 'mail', + 'managers_regress', + 'many_to_many', + 'many_to_one', + 'many_to_one_null', + 'max_lengths', + # TODO: 'messages_tests', + # TODO: 'middleware', + # TODO: 'middleware_exceptions', + # SKIPPED (all errors are false positives) 'migrate_signals', + 'migration_test_data_persistence', + # TODO: 'migrations', + 'migrations2', + # TODO: 'model_fields', + # TODO: 'model_forms', + 'model_formsets', + 'model_formsets_regress', + 'model_indexes', + # TODO: 'model_inheritance', + 'model_inheritance_regress', + # SKIPPED (all errors are false positives) 'model_meta', + 'model_options', + 'model_package', + 'model_regress', + # TODO: 'modeladmin', + # TODO: 'multiple_database', + 'mutually_referential', + 'nested_foreign_keys', ]