mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-11 22:41:55 +08:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ea25f3e56 | ||
|
|
dacf88c692 | ||
|
|
3d14d07e4e | ||
|
|
6e6d1645d3 | ||
|
|
2bd018951b | ||
|
|
14ea848dd7 | ||
|
|
2d3b5492f0 | ||
|
|
194258ab8e | ||
|
|
116aa2c539 | ||
|
|
67c99434e5 | ||
|
|
5d8cdbcf29 | ||
|
|
78810f55b6 | ||
|
|
36662896bc | ||
|
|
e54dbb79c9 | ||
|
|
41f283552a | ||
|
|
ab73d53ae5 | ||
|
|
d24be4b35f | ||
|
|
9d60b472df | ||
|
|
632e063e22 | ||
|
|
66224416b5 | ||
|
|
e5b2496eb5 | ||
|
|
f980311be0 | ||
|
|
400a0f0486 | ||
|
|
882ec71d23 | ||
|
|
e9f9202ed1 | ||
|
|
6763217a80 | ||
|
|
6da5ead6f0 | ||
|
|
c382d6aa2f | ||
|
|
63a14f7107 | ||
|
|
dc33dd9493 |
@@ -7,6 +7,10 @@
|
||||
|
||||
This package contains type stubs and mypy plugin to provide more precise static types and type inference for Django framework. Django uses some Python "magic" that makes having precise types for some code patterns problematic. This is why we need to accompany the stubs with mypy plugins. The final goal is to be able to get precise types for most common patterns.
|
||||
|
||||
Supports Python 3.6/3.7, and Django 2.1.x series.
|
||||
|
||||
Could be run on earlier versions of Django, but expect some missing imports warnings.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
black
|
||||
-e git+https://github.com/mkurnikov/pytest-mypy-plugins.git#egg=pytest-mypy-plugins
|
||||
pytest-mypy-plugins
|
||||
-e .
|
||||
|
||||
@@ -12,7 +12,7 @@ class AppConfig:
|
||||
verbose_name: str = ...
|
||||
path: str = ...
|
||||
models_module: None = ...
|
||||
models: Optional[Dict[str, Type[Model]]] = ...
|
||||
models: Dict[str, Type[Model]] = ...
|
||||
def __init__(self, app_name: str, app_module: Optional[Any]) -> None: ...
|
||||
@classmethod
|
||||
def create(cls, entry: str) -> AppConfig: ...
|
||||
|
||||
@@ -5,7 +5,7 @@ by the DJANGO_SETTINGS_MODULE environment variable.
|
||||
|
||||
# This is defined here as a do-nothing function because we can't import
|
||||
# django.utils.translation -- that module depends on the settings.
|
||||
from typing import Any, Dict, List, Optional, Pattern, Tuple, Protocol, Union, Callable, TYPE_CHECKING
|
||||
from typing import Any, Dict, List, Optional, Pattern, Tuple, Protocol, Union, Callable, TYPE_CHECKING, Sequence
|
||||
|
||||
####################
|
||||
# CORE #
|
||||
@@ -377,7 +377,7 @@ CACHE_MIDDLEWARE_ALIAS = "default"
|
||||
|
||||
AUTH_USER_MODEL: str = ...
|
||||
|
||||
AUTHENTICATION_BACKENDS: List[str] = ...
|
||||
AUTHENTICATION_BACKENDS: Sequence[str] = ...
|
||||
|
||||
LOGIN_URL = "/accounts/login/"
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class LogEntryManager(models.Manager["LogEntry"]):
|
||||
class LogEntry(models.Model):
|
||||
action_time: models.DateTimeField = ...
|
||||
user: models.ForeignKey = ...
|
||||
content_type: models.ForeignKey[ContentType] = ...
|
||||
content_type: models.ForeignKey = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
||||
object_id: models.TextField = ...
|
||||
object_repr: models.CharField = ...
|
||||
action_flag: models.PositiveSmallIntegerField = ...
|
||||
|
||||
@@ -57,14 +57,20 @@ class BaseModelAdmin:
|
||||
checks_class: Any = ...
|
||||
def check(self, **kwargs: Any) -> List[Union[str, Error]]: ...
|
||||
def __init__(self) -> None: ...
|
||||
def formfield_for_dbfield(self, db_field: Field, request: WSGIRequest, **kwargs: Any) -> Optional[Field]: ...
|
||||
def formfield_for_choice_field(self, db_field: Field, request: WSGIRequest, **kwargs: Any) -> TypedChoiceField: ...
|
||||
def get_field_queryset(self, db: None, db_field: RelatedField, request: WSGIRequest) -> Optional[QuerySet]: ...
|
||||
def formfield_for_dbfield(
|
||||
self, db_field: Field, request: Optional[WSGIRequest], **kwargs: Any
|
||||
) -> Optional[Field]: ...
|
||||
def formfield_for_choice_field(
|
||||
self, db_field: Field, request: Optional[WSGIRequest], **kwargs: Any
|
||||
) -> TypedChoiceField: ...
|
||||
def get_field_queryset(
|
||||
self, db: None, db_field: RelatedField, request: Optional[WSGIRequest]
|
||||
) -> Optional[QuerySet]: ...
|
||||
def formfield_for_foreignkey(
|
||||
self, db_field: ForeignKey, request: WSGIRequest, **kwargs: Any
|
||||
self, db_field: ForeignKey, request: Optional[WSGIRequest], **kwargs: Any
|
||||
) -> Optional[ModelChoiceField]: ...
|
||||
def formfield_for_manytomany(
|
||||
self, db_field: ManyToManyField, request: WSGIRequest, **kwargs: Any
|
||||
self, db_field: ManyToManyField, request: Optional[WSGIRequest], **kwargs: Any
|
||||
) -> ModelMultipleChoiceField: ...
|
||||
def get_autocomplete_fields(self, request: WSGIRequest) -> Tuple: ...
|
||||
def get_view_on_site_url(self, obj: Optional[Model] = ...) -> Optional[str]: ...
|
||||
@@ -90,7 +96,7 @@ class BaseModelAdmin:
|
||||
class ModelAdmin(BaseModelAdmin):
|
||||
formfield_overrides: Any
|
||||
list_display: Sequence[Union[str, Callable]] = ...
|
||||
list_display_links: Sequence[Union[str, Callable]] = ...
|
||||
list_display_links: Optional[Sequence[Union[str, Callable]]] = ...
|
||||
list_filter: Sequence[Union[str, Type[ListFilter], Tuple[str, Type[ListFilter]]]] = ...
|
||||
list_select_related: Union[bool, Sequence[str]] = ...
|
||||
list_per_page: int = ...
|
||||
|
||||
@@ -43,7 +43,7 @@ class NestedObjects(Collector):
|
||||
def add_edge(self, source: Optional[Model], target: Model) -> None: ...
|
||||
def collect(
|
||||
self,
|
||||
objs: Union[Sequence[Model], QuerySet],
|
||||
objs: Union[Sequence[Optional[Model]], QuerySet],
|
||||
source: Optional[Type[Model]] = ...,
|
||||
source_attr: Optional[str] = ...,
|
||||
**kwargs: Any
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
||||
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.db.models.fields import Field
|
||||
from django.db.models.fields.related import ManyToManyField
|
||||
from django.db.models.options import Options
|
||||
from django.forms.models import ModelMultipleChoiceField
|
||||
from django.forms.fields import Field as FormField
|
||||
from django.forms.widgets import Widget
|
||||
from django.http.response import HttpResponse
|
||||
from django.urls.resolvers import URLPattern
|
||||
|
||||
@@ -27,10 +31,7 @@ class GroupAdmin(admin.ModelAdmin):
|
||||
|
||||
class UserAdmin(admin.ModelAdmin):
|
||||
admin_site: AdminSite
|
||||
formfield_overrides: Dict[
|
||||
Type[Union[django.db.models.fields.DateTimeCheckMixin, Field]],
|
||||
Dict[str, Type[Union[django.forms.fields.SplitDateTimeField, Widget]]],
|
||||
]
|
||||
formfield_overrides: Dict[Type[Field], Dict[str, Type[Union[FormField, Widget]]]]
|
||||
model: Type[User]
|
||||
opts: Options
|
||||
add_form_template: str = ...
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Any, Callable, List, Optional
|
||||
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django import http
|
||||
from django.http.response import HttpResponse, HttpResponseRedirect
|
||||
|
||||
class AccessMixin:
|
||||
@@ -14,15 +14,15 @@ class AccessMixin:
|
||||
def handle_no_permission(self) -> HttpResponseRedirect: ...
|
||||
|
||||
class LoginRequiredMixin(AccessMixin):
|
||||
def dispatch(self, request: WSGIRequest, *args: Any, **kwargs: Any) -> HttpResponse: ...
|
||||
def dispatch(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: ...
|
||||
|
||||
class PermissionRequiredMixin(AccessMixin):
|
||||
permission_required: Any = ...
|
||||
def get_permission_required(self) -> List[str]: ...
|
||||
def has_permission(self) -> bool: ...
|
||||
def dispatch(self, request: WSGIRequest, *args: Any, **kwargs: Any) -> HttpResponse: ...
|
||||
def dispatch(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: ...
|
||||
|
||||
class UserPassesTestMixin(AccessMixin):
|
||||
def test_func(self) -> None: ...
|
||||
def get_test_func(self) -> Callable: ...
|
||||
def dispatch(self, request: WSGIRequest, *args: Any, **kwargs: Any) -> HttpResponse: ...
|
||||
def dispatch(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: ...
|
||||
|
||||
@@ -15,7 +15,7 @@ class PermissionManager(models.Manager):
|
||||
class Permission(models.Model):
|
||||
content_type_id: int
|
||||
name: models.CharField = ...
|
||||
content_type: models.ForeignKey[ContentType] = ...
|
||||
content_type: models.ForeignKey = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
||||
codename: models.CharField = ...
|
||||
def natural_key(self) -> Tuple[str, str, str]: ...
|
||||
|
||||
@@ -24,7 +24,7 @@ class GroupManager(models.Manager):
|
||||
|
||||
class Group(models.Model):
|
||||
name: models.CharField = ...
|
||||
permissions: models.ManyToManyField[Permission] = ...
|
||||
permissions: models.ManyToManyField = models.ManyToManyField(Permission)
|
||||
def natural_key(self): ...
|
||||
|
||||
class UserManager(BaseUserManager):
|
||||
@@ -37,8 +37,8 @@ class UserManager(BaseUserManager):
|
||||
|
||||
class PermissionsMixin(models.Model):
|
||||
is_superuser: models.BooleanField = ...
|
||||
groups: models.ManyToManyField[Group] = ...
|
||||
user_permissions: models.ManyToManyField[Permission] = ...
|
||||
groups: models.ManyToManyField = models.ManyToManyField(Group)
|
||||
user_permissions: models.ManyToManyField = models.ManyToManyField(Permission)
|
||||
def get_group_permissions(self, obj: None = ...) -> Set[str]: ...
|
||||
def get_all_permissions(self, obj: Optional[str] = ...) -> Set[str]: ...
|
||||
def has_perm(self, perm: Union[Tuple[str, Any], str], obj: Optional[str] = ...) -> bool: ...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union, Generic
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.checks.messages import Error
|
||||
|
||||
@@ -1,20 +1,51 @@
|
||||
from typing import Any, Generic, List, Optional, Sequence, TypeVar
|
||||
from typing import Any, Iterable, List, Optional, Sequence, TypeVar, Union
|
||||
|
||||
from django.db.models.expressions import Combinable
|
||||
from django.db.models.fields import Field, _ErrorMessagesToOverride, _FieldChoices, _ValidatorCallable
|
||||
|
||||
from django.db.models.fields import Field
|
||||
from .mixins import CheckFieldDefaultMixin
|
||||
|
||||
_T = TypeVar("_T", bound=Field)
|
||||
# __set__ value type
|
||||
_ST = TypeVar("_ST")
|
||||
# __get__ return type
|
||||
_GT = TypeVar("_GT")
|
||||
|
||||
class ArrayField(CheckFieldDefaultMixin, Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[Sequence[Any], Combinable]
|
||||
_pyi_private_get_type: List[Any]
|
||||
|
||||
class ArrayField(CheckFieldDefaultMixin, Field, Generic[_T]):
|
||||
empty_strings_allowed: bool = ...
|
||||
default_error_messages: Any = ...
|
||||
base_field: Any = ...
|
||||
size: Any = ...
|
||||
default_validators: Any = ...
|
||||
from_db_value: Any = ...
|
||||
def __init__(self, base_field: _T, size: Optional[int] = ..., **kwargs: Any) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
base_field: Field,
|
||||
size: Optional[int] = ...,
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
name: Optional[str] = ...,
|
||||
primary_key: bool = ...,
|
||||
max_length: Optional[int] = ...,
|
||||
unique: bool = ...,
|
||||
blank: bool = ...,
|
||||
null: bool = ...,
|
||||
db_index: bool = ...,
|
||||
default: Any = ...,
|
||||
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] = ...,
|
||||
db_tablespace: Optional[str] = ...,
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
) -> None: ...
|
||||
@property
|
||||
def description(self): ...
|
||||
def get_transform(self, name: Any): ...
|
||||
def __set__(self, instance, value: Sequence[_T]) -> None: ...
|
||||
def __get__(self, instance, owner) -> List[_T]: ...
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union
|
||||
from typing import Any, Dict, Iterator, List, Mapping, Optional, Tuple, Union
|
||||
|
||||
from django.db.models.base import Model
|
||||
from django.forms.utils import ErrorDict
|
||||
|
||||
class FieldDoesNotExist(Exception): ...
|
||||
@@ -31,20 +30,13 @@ class ValidationError(Exception):
|
||||
message: Any = ...
|
||||
code: Any = ...
|
||||
params: Any = ...
|
||||
def __init__(
|
||||
self,
|
||||
message: Any,
|
||||
code: Optional[str] = ...,
|
||||
params: Optional[
|
||||
Union[Dict[str, Union[Tuple[str], Type[Model], Model, str]], Dict[str, Union[int, str]]]
|
||||
] = ...,
|
||||
) -> None: ...
|
||||
def __init__(self, message: Any, code: Optional[str] = ..., params: Optional[Mapping[str, Any]] = ...) -> None: ...
|
||||
@property
|
||||
def message_dict(self) -> Dict[str, List[str]]: ...
|
||||
@property
|
||||
def messages(self) -> List[str]: ...
|
||||
def update_error_dict(
|
||||
self, error_dict: Union[Dict[str, List[ValidationError]], ErrorDict]
|
||||
self, error_dict: Mapping[str, Any]
|
||||
) -> Union[Dict[str, List[ValidationError]], ErrorDict]: ...
|
||||
def __iter__(self) -> Iterator[Union[Tuple[str, List[str]], str]]: ...
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ class InMemoryUploadedFile(UploadedFile):
|
||||
charset: Optional[str],
|
||||
content_type_extra: Dict[str, str] = ...,
|
||||
) -> None: ...
|
||||
def chunks(self, chunk_size: int = None) -> Iterator[bytes]: ...
|
||||
def multiple_chunks(self, chunk_size: int = None) -> bool: ...
|
||||
def chunks(self, chunk_size: Optional[int] = ...) -> Iterator[bytes]: ...
|
||||
def multiple_chunks(self, chunk_size: Optional[int] = ...) -> bool: ...
|
||||
|
||||
class SimpleUploadedFile(InMemoryUploadedFile):
|
||||
def __init__(self, name: str, content: bytes, content_type: str = "") -> None: ...
|
||||
def __init__(self, name: str, content: Optional[Union[bytes, str]], content_type: str = ...) -> None: ...
|
||||
@classmethod
|
||||
def from_dict(cls: Any, file_dict: Dict[str, Union[str, bytes]]) -> None: ...
|
||||
|
||||
@@ -46,12 +46,12 @@ class FieldRelatedOptionOperation(ModelOptionOperation): ...
|
||||
class AlterUniqueTogether(FieldRelatedOptionOperation):
|
||||
option_name: str = ...
|
||||
unique_together: Collection[Sequence[str]] = ...
|
||||
def __init__(self, name: str, unique_together: Collection[Sequence[str]]) -> None: ...
|
||||
def __init__(self, name: str, unique_together: Optional[Collection[Sequence[str]]]) -> None: ...
|
||||
|
||||
class AlterIndexTogether(FieldRelatedOptionOperation):
|
||||
option_name: str = ...
|
||||
index_together: Collection[Sequence[str]] = ...
|
||||
def __init__(self, name: str, index_together: Collection[Sequence[str]]) -> None: ...
|
||||
def __init__(self, name: str, index_together: Optional[Collection[Sequence[str]]]) -> None: ...
|
||||
|
||||
class AlterOrderWithRespectTo(FieldRelatedOptionOperation):
|
||||
order_with_respect_to: str = ...
|
||||
|
||||
@@ -22,9 +22,9 @@ 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]]] = ...
|
||||
options: Dict[str, Any] = ...
|
||||
bases: Tuple[Type[Model]] = ...
|
||||
managers: List[Tuple[str, Manager]] = ...
|
||||
def __init__(
|
||||
self,
|
||||
app_label: str,
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import uuid
|
||||
from datetime import date, time, datetime, timedelta
|
||||
from typing import Any, Optional, Tuple, Iterable, Callable, Dict, Union, Type, TypeVar, Generic
|
||||
import decimal
|
||||
|
||||
from typing_extensions import Literal
|
||||
import uuid
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from typing import Any, Callable, Dict, Generic, Iterable, Optional, Tuple, Type, TypeVar, Union
|
||||
|
||||
from django.db.models import Model
|
||||
from django.db.models.query_utils import RegisterLookupMixin
|
||||
|
||||
from django.db.models.expressions import F, Combinable
|
||||
from django.core.exceptions import FieldDoesNotExist as FieldDoesNotExist
|
||||
from django.forms import Widget, Field as FormField
|
||||
from django.db.models.expressions import Combinable
|
||||
from django.db.models.query_utils import RegisterLookupMixin
|
||||
from django.forms import Field as FormField, Widget
|
||||
|
||||
from .mixins import NOT_PROVIDED as NOT_PROVIDED
|
||||
|
||||
_Choice = Tuple[Any, Any]
|
||||
@@ -20,7 +18,15 @@ _FieldChoices = Iterable[Union[_Choice, _ChoiceNamedGroup]]
|
||||
_ValidatorCallable = Callable[..., None]
|
||||
_ErrorMessagesToOverride = Dict[str, Any]
|
||||
|
||||
class Field(RegisterLookupMixin):
|
||||
# __set__ value type
|
||||
_ST = TypeVar("_ST")
|
||||
# __get__ return type
|
||||
_GT = TypeVar("_GT")
|
||||
|
||||
class Field(RegisterLookupMixin, Generic[_ST, _GT]):
|
||||
_pyi_private_set_type: Any
|
||||
_pyi_private_get_type: Any
|
||||
|
||||
widget: Widget
|
||||
help_text: str
|
||||
db_table: str
|
||||
@@ -52,7 +58,8 @@ class Field(RegisterLookupMixin):
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
def __get__(self, instance, owner) -> Any: ...
|
||||
def __set__(self, instance, value: _ST) -> None: ...
|
||||
def __get__(self, instance, owner) -> _GT: ...
|
||||
def deconstruct(self) -> Any: ...
|
||||
def set_attributes_from_name(self, name: str) -> None: ...
|
||||
def db_type(self, connection: Any) -> str: ...
|
||||
@@ -63,23 +70,25 @@ class Field(RegisterLookupMixin):
|
||||
def contribute_to_class(self, cls: Type[Model], name: str, private_only: bool = ...) -> None: ...
|
||||
def to_python(self, value: Any) -> Any: ...
|
||||
|
||||
class IntegerField(Field):
|
||||
def __set__(self, instance, value: Union[int, Combinable, Literal[""]]) -> None: ...
|
||||
def __get__(self, instance, owner) -> int: ...
|
||||
class IntegerField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[float, int, str, Combinable]
|
||||
_pyi_private_get_type: int
|
||||
|
||||
class PositiveIntegerRelDbTypeMixin:
|
||||
def rel_db_type(self, connection: Any): ...
|
||||
|
||||
class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): ...
|
||||
class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): ...
|
||||
class SmallIntegerField(IntegerField): ...
|
||||
class BigIntegerField(IntegerField): ...
|
||||
class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField[_ST, _GT]): ...
|
||||
class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField[_ST, _GT]): ...
|
||||
class SmallIntegerField(IntegerField[_ST, _GT]): ...
|
||||
class BigIntegerField(IntegerField[_ST, _GT]): ...
|
||||
|
||||
class FloatField(Field):
|
||||
def __set__(self, instance, value: Union[float, int, str, Combinable]) -> float: ...
|
||||
def __get__(self, instance, owner) -> float: ...
|
||||
class FloatField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[float, int, str, Combinable]
|
||||
_pyi_private_get_type: float
|
||||
|
||||
class DecimalField(Field):
|
||||
class DecimalField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[str, float, decimal.Decimal, Combinable]
|
||||
_pyi_private_get_type: decimal.Decimal
|
||||
def __init__(
|
||||
self,
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
@@ -102,13 +111,14 @@ class DecimalField(Field):
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
def __set__(self, instance, value: Union[str, float, decimal.Decimal, Combinable]) -> decimal.Decimal: ...
|
||||
def __get__(self, instance, owner) -> decimal.Decimal: ...
|
||||
|
||||
class AutoField(Field):
|
||||
def __get__(self, instance, owner) -> int: ...
|
||||
class AutoField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[Combinable, int, str]
|
||||
_pyi_private_get_type: int
|
||||
|
||||
class CharField(Field):
|
||||
class CharField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[str, int, Combinable]
|
||||
_pyi_private_get_type: str
|
||||
def __init__(
|
||||
self,
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
@@ -133,10 +143,8 @@ class CharField(Field):
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
def __set__(self, instance, value: Union[str, int, Combinable]) -> None: ...
|
||||
def __get__(self, instance, owner) -> str: ...
|
||||
|
||||
class SlugField(CharField):
|
||||
class SlugField(CharField[_ST, _GT]):
|
||||
def __init__(
|
||||
self,
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
@@ -163,25 +171,29 @@ class SlugField(CharField):
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
|
||||
class EmailField(CharField): ...
|
||||
class URLField(CharField): ...
|
||||
class EmailField(CharField[_ST, _GT]): ...
|
||||
class URLField(CharField[_ST, _GT]): ...
|
||||
|
||||
class TextField(Field):
|
||||
def __set__(self, instance, value: Union[str, Combinable]) -> None: ...
|
||||
def __get__(self, instance, owner) -> str: ...
|
||||
class TextField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[str, Combinable]
|
||||
_pyi_private_get_type: str
|
||||
|
||||
class BooleanField(Field):
|
||||
def __set__(self, instance, value: Union[bool, Combinable]) -> None: ...
|
||||
def __get__(self, instance, owner) -> bool: ...
|
||||
class BooleanField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[bool, Combinable]
|
||||
_pyi_private_get_type: bool
|
||||
|
||||
class NullBooleanField(Field):
|
||||
def __set__(self, instance, value: Optional[Union[bool, Combinable]]) -> None: ...
|
||||
def __get__(self, instance, owner) -> Optional[bool]: ...
|
||||
class NullBooleanField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Optional[Union[bool, Combinable]]
|
||||
_pyi_private_get_type: Optional[bool]
|
||||
|
||||
class IPAddressField(Field):
|
||||
def __get__(self, instance, owner) -> str: ...
|
||||
class IPAddressField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[str, Combinable]
|
||||
_pyi_private_get_type: str
|
||||
|
||||
class GenericIPAddressField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[str, int, Callable[..., Any], Combinable]
|
||||
_pyi_private_get_type: str
|
||||
|
||||
class GenericIPAddressField(Field):
|
||||
default_error_messages: Any = ...
|
||||
unpack_ipv4: Any = ...
|
||||
protocol: Any = ...
|
||||
@@ -207,12 +219,12 @@ class GenericIPAddressField(Field):
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
) -> None: ...
|
||||
def __set__(self, instance, value: Union[str, int, Callable[..., Any], Combinable]): ...
|
||||
def __get__(self, instance, owner) -> str: ...
|
||||
|
||||
class DateTimeCheckMixin: ...
|
||||
|
||||
class DateField(DateTimeCheckMixin, Field):
|
||||
class DateField(DateTimeCheckMixin, Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[str, date, Combinable]
|
||||
_pyi_private_get_type: date
|
||||
def __init__(
|
||||
self,
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
@@ -236,10 +248,10 @@ class DateField(DateTimeCheckMixin, Field):
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
def __set__(self, instance, value: Union[str, date, Combinable]) -> None: ...
|
||||
def __get__(self, instance, owner) -> date: ...
|
||||
|
||||
class TimeField(DateTimeCheckMixin, Field):
|
||||
class TimeField(DateTimeCheckMixin, Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[str, time, datetime, Combinable]
|
||||
_pyi_private_get_type: time
|
||||
def __init__(
|
||||
self,
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
@@ -262,18 +274,15 @@ class TimeField(DateTimeCheckMixin, Field):
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
def __set__(self, instance, value: Union[str, time, datetime, Combinable]) -> None: ...
|
||||
def __get__(self, instance, owner) -> time: ...
|
||||
|
||||
class DateTimeField(DateField):
|
||||
def __set__(self, instance, value: Union[str, date, datetime, Combinable]) -> None: ...
|
||||
def __get__(self, instance, owner) -> datetime: ...
|
||||
class DateTimeField(DateField[_ST, _GT]):
|
||||
_pyi_private_get_type: datetime
|
||||
|
||||
class UUIDField(Field):
|
||||
def __set__(self, instance, value: Union[str, uuid.UUID]) -> None: ...
|
||||
def __get__(self, instance, owner) -> uuid.UUID: ...
|
||||
class UUIDField(Field[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[str, uuid.UUID]
|
||||
_pyi_private_get_type: uuid.UUID
|
||||
|
||||
class FilePathField(Field):
|
||||
class FilePathField(Field[_ST, _GT]):
|
||||
path: str = ...
|
||||
match: Optional[Any] = ...
|
||||
recursive: bool = ...
|
||||
@@ -306,10 +315,10 @@ class FilePathField(Field):
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
|
||||
class BinaryField(Field): ...
|
||||
class BinaryField(Field[_ST, _GT]): ...
|
||||
|
||||
class DurationField(Field):
|
||||
def __get__(self, instance, owner) -> timedelta: ...
|
||||
class DurationField(Field[_ST, _GT]):
|
||||
_pyi_private_get_type: timedelta
|
||||
|
||||
class BigAutoField(AutoField): ...
|
||||
class CommaSeparatedIntegerField(CharField): ...
|
||||
class BigAutoField(AutoField[_ST, _GT]): ...
|
||||
class CommaSeparatedIntegerField(CharField[_ST, _GT]): ...
|
||||
|
||||
@@ -49,7 +49,12 @@ _ErrorMessagesToOverride = Dict[str, Any]
|
||||
|
||||
RECURSIVE_RELATIONSHIP_CONSTANT: str = ...
|
||||
|
||||
class RelatedField(FieldCacheMixin, Field):
|
||||
# __set__ value type
|
||||
_ST = TypeVar("_ST")
|
||||
# __get__ return type
|
||||
_GT = TypeVar("_GT")
|
||||
|
||||
class RelatedField(FieldCacheMixin, Field[_ST, _GT]):
|
||||
one_to_many: bool = ...
|
||||
one_to_one: bool = ...
|
||||
many_to_many: bool = ...
|
||||
@@ -83,6 +88,7 @@ class ForeignObject(RelatedField):
|
||||
related_query_name: None = ...,
|
||||
limit_choices_to: Optional[Union[Dict[str, Any], Callable[[], Any]]] = ...,
|
||||
parent_link: bool = ...,
|
||||
db_constraint: bool = ...,
|
||||
swappable: bool = ...,
|
||||
verbose_name: Optional[str] = ...,
|
||||
name: Optional[str] = ...,
|
||||
@@ -103,17 +109,82 @@ class ForeignObject(RelatedField):
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
|
||||
class ForeignKey(RelatedField, Generic[_T]):
|
||||
def __init__(self, to: Union[Type[_T], str], on_delete: Any, related_name: str = ..., **kwargs): ...
|
||||
def __set__(self, instance, value: Union[Model, Combinable]) -> None: ...
|
||||
def __get__(self, instance, owner) -> _T: ...
|
||||
class ForeignKey(RelatedField[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[Any, Combinable]
|
||||
_pyi_private_get_type: Any
|
||||
def __init__(
|
||||
self,
|
||||
to: Union[Type[Model], str],
|
||||
on_delete: Callable[..., None],
|
||||
to_field: Optional[str] = ...,
|
||||
related_name: str = ...,
|
||||
related_query_name: Optional[str] = ...,
|
||||
limit_choices_to: Optional[Union[Dict[str, Any], Callable[[], Any], Q]] = ...,
|
||||
parent_link: bool = ...,
|
||||
db_constraint: bool = ...,
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
name: Optional[str] = ...,
|
||||
primary_key: bool = ...,
|
||||
max_length: Optional[int] = ...,
|
||||
unique: bool = ...,
|
||||
blank: bool = ...,
|
||||
null: bool = ...,
|
||||
db_index: bool = ...,
|
||||
default: Any = ...,
|
||||
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] = ...,
|
||||
db_tablespace: Optional[str] = ...,
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
|
||||
class OneToOneField(RelatedField, Generic[_T]):
|
||||
def __init__(self, to: Union[Type[_T], str], on_delete: Any, related_name: str = ..., **kwargs): ...
|
||||
def __set__(self, instance, value: Union[Model, Combinable]) -> None: ...
|
||||
def __get__(self, instance, owner) -> _T: ...
|
||||
class OneToOneField(RelatedField[_ST, _GT]):
|
||||
_pyi_private_set_type: Union[Any, Combinable]
|
||||
_pyi_private_get_type: Any
|
||||
def __init__(
|
||||
self,
|
||||
to: Union[Type[Model], str],
|
||||
on_delete: Any,
|
||||
to_field: Optional[str] = ...,
|
||||
related_name: str = ...,
|
||||
related_query_name: Optional[str] = ...,
|
||||
limit_choices_to: Optional[Union[Dict[str, Any], Callable[[], Any], Q]] = ...,
|
||||
parent_link: bool = ...,
|
||||
db_constraint: bool = ...,
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
name: Optional[str] = ...,
|
||||
primary_key: bool = ...,
|
||||
max_length: Optional[int] = ...,
|
||||
unique: bool = ...,
|
||||
blank: bool = ...,
|
||||
null: bool = ...,
|
||||
db_index: bool = ...,
|
||||
default: Any = ...,
|
||||
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] = ...,
|
||||
db_tablespace: Optional[str] = ...,
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
): ...
|
||||
|
||||
class ManyToManyField(RelatedField[_ST, _GT]):
|
||||
_pyi_private_set_type: Sequence[Any]
|
||||
_pyi_private_get_type: RelatedManager[Any]
|
||||
|
||||
class ManyToManyField(RelatedField, Generic[_T]):
|
||||
many_to_many: bool = ...
|
||||
many_to_one: bool = ...
|
||||
one_to_many: bool = ...
|
||||
@@ -127,17 +198,35 @@ class ManyToManyField(RelatedField, Generic[_T]):
|
||||
to: Union[Type[_T], str],
|
||||
related_name: Optional[str] = ...,
|
||||
related_query_name: Optional[str] = ...,
|
||||
limit_choices_to: Optional[Union[Dict[str, Any], Callable[[], Any]]] = ...,
|
||||
limit_choices_to: Optional[Union[Dict[str, Any], Callable[[], Any], Q]] = ...,
|
||||
symmetrical: Optional[bool] = ...,
|
||||
through: Optional[Union[str, Type[Model]]] = ...,
|
||||
through_fields: Optional[Tuple[str, str]] = ...,
|
||||
db_constraint: bool = ...,
|
||||
db_table: Optional[str] = ...,
|
||||
swappable: bool = ...,
|
||||
**kwargs: Any
|
||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||
name: Optional[str] = ...,
|
||||
primary_key: bool = ...,
|
||||
max_length: Optional[int] = ...,
|
||||
unique: bool = ...,
|
||||
blank: bool = ...,
|
||||
null: bool = ...,
|
||||
db_index: bool = ...,
|
||||
default: Any = ...,
|
||||
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] = ...,
|
||||
db_tablespace: Optional[str] = ...,
|
||||
validators: Iterable[_ValidatorCallable] = ...,
|
||||
error_messages: Optional[_ErrorMessagesToOverride] = ...,
|
||||
) -> None: ...
|
||||
def __set__(self, instance, value: Sequence[_T]) -> None: ...
|
||||
def __get__(self, instance, owner) -> RelatedManager[_T]: ...
|
||||
def check(self, **kwargs: Any) -> List[Any]: ...
|
||||
def deconstruct(self) -> Tuple[Optional[str], str, List[Any], Dict[str, str]]: ...
|
||||
def get_path_info(self, filtered_relation: None = ...) -> List[PathInfo]: ...
|
||||
|
||||
@@ -4,7 +4,6 @@ from django.db.models.base import Model
|
||||
from django.db.models.query import QuerySet
|
||||
|
||||
_T = TypeVar("_T", bound=Model, covariant=True)
|
||||
_Self = TypeVar("_Self", bound="BaseManager")
|
||||
|
||||
class BaseManager(QuerySet[_T]):
|
||||
creation_counter: int = ...
|
||||
@@ -17,9 +16,7 @@ class BaseManager(QuerySet[_T]):
|
||||
def deconstruct(self) -> Tuple[bool, str, None, Tuple, Dict[str, int]]: ...
|
||||
def check(self, **kwargs: Any) -> List[Any]: ...
|
||||
@classmethod
|
||||
def from_queryset(
|
||||
cls: Type[_Self], queryset_class: Type[QuerySet], class_name: Optional[str] = ...
|
||||
) -> Type[_Self]: ...
|
||||
def from_queryset(cls, queryset_class: Type[QuerySet], class_name: Optional[str] = ...) -> Any: ...
|
||||
@classmethod
|
||||
def _get_queryset_methods(cls, queryset_class: type) -> Dict[str, Any]: ...
|
||||
def contribute_to_class(self, model: Type[Model], name: str) -> None: ...
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from contextlib import ContextDecorator
|
||||
from typing import Any, Callable, Optional, Union, Iterator, overload, ContextManager
|
||||
from typing import Any, Callable, Optional, overload, TypeVar
|
||||
|
||||
from django.db import ProgrammingError
|
||||
|
||||
@@ -18,19 +17,23 @@ def get_rollback(using: None = ...) -> bool: ...
|
||||
def set_rollback(rollback: bool, using: Optional[str] = ...) -> None: ...
|
||||
def on_commit(func: Callable, using: None = ...) -> None: ...
|
||||
|
||||
class Atomic(ContextDecorator):
|
||||
_C = TypeVar("_C", bound=Callable) # Any callable
|
||||
|
||||
# Don't inherit from ContextDecorator, so we can provide a more specific signature for __call__
|
||||
class Atomic:
|
||||
using: Optional[str] = ...
|
||||
savepoint: bool = ...
|
||||
def __init__(self, using: Optional[str], savepoint: bool) -> None: ...
|
||||
# When decorating, return the decorated function as-is, rather than clobbering it as ContextDecorator does.
|
||||
def __call__(self, func: _C) -> _C: ...
|
||||
def __enter__(self) -> None: ...
|
||||
def __exit__(self, exc_type: None, exc_value: None, traceback: None) -> None: ...
|
||||
|
||||
# Bare decorator
|
||||
@overload
|
||||
def atomic() -> Atomic: ...
|
||||
def atomic(using: _C) -> _C: ...
|
||||
|
||||
# Decorator or context-manager with parameters
|
||||
@overload
|
||||
def atomic(using: Optional[str] = ...,) -> ContextManager[Atomic]: ...
|
||||
@overload
|
||||
def atomic(using: Callable = ...) -> Callable: ...
|
||||
@overload
|
||||
def atomic(using: Optional[str] = ..., savepoint: bool = ...) -> ContextManager[Atomic]: ...
|
||||
def atomic(using: Optional[str] = None, savepoint: bool = True) -> Atomic: ...
|
||||
def non_atomic_requests(using: Callable = ...) -> Callable: ...
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import decimal
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, Type
|
||||
from uuid import UUID
|
||||
from typing import Any, Callable, List, Optional, Pattern, Sequence, Type, Union
|
||||
|
||||
from django.core.files.base import File
|
||||
from django.core.validators import BaseValidator
|
||||
from django.db.models.fields.files import FieldFile
|
||||
from django.forms.boundfield import BoundField
|
||||
from django.forms.forms import BaseForm
|
||||
from django.forms.widgets import Widget
|
||||
@@ -31,16 +27,16 @@ class Field:
|
||||
self,
|
||||
*,
|
||||
required: bool = ...,
|
||||
widget: Optional[Any] = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Any = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
def prepare_value(self, value: Any) -> Any: ...
|
||||
def to_python(self, value: Optional[Any]) -> Optional[Any]: ...
|
||||
@@ -49,60 +45,60 @@ class Field:
|
||||
def clean(self, value: Any) -> Any: ...
|
||||
def bound_data(self, data: Any, initial: Any) -> Any: ...
|
||||
def widget_attrs(self, widget: Widget) -> Any: ...
|
||||
def has_changed(self, initial: Any, data: Optional[str]) -> bool: ...
|
||||
def has_changed(self, initial: Any, data: Any) -> bool: ...
|
||||
def get_bound_field(self, form: BaseForm, field_name: str) -> BoundField: ...
|
||||
def __deepcopy__(self, memo: Dict[Any, Any]) -> Field: ...
|
||||
|
||||
class CharField(Field):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
max_length: Optional[Union[int, str]] = ...
|
||||
min_length: Optional[Union[int, str]] = ...
|
||||
strip: bool = ...
|
||||
empty_value: Optional[str] = ...
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
max_length: Optional[Any] = ...,
|
||||
min_length: Optional[Any] = ...,
|
||||
strip: bool = ...,
|
||||
empty_value: str = ...,
|
||||
**kwargs: Any
|
||||
empty_value: Optional[str] = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class IntegerField(Field):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
max_value: Optional[Any]
|
||||
min_value: Optional[Any]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
default_error_messages: Any = ...
|
||||
re_decimal: Any = ...
|
||||
def __init__(self, *, max_value: Optional[Any] = ..., min_value: Optional[Any] = ..., **kwargs: Any) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
max_value: Optional[Any] = ...,
|
||||
min_value: Optional[Any] = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class FloatField(IntegerField):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
max_value: Optional[float]
|
||||
min_value: Optional[float]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
default_error_messages: Any = ...
|
||||
def validate(self, value: Optional[float]) -> None: ...
|
||||
|
||||
class DecimalField(IntegerField):
|
||||
decimal_places: Optional[int]
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
max_digits: Optional[int]
|
||||
max_value: Optional[Union[decimal.Decimal, int]]
|
||||
min_value: Optional[Union[decimal.Decimal, int]]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
default_error_messages: Any = ...
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -110,118 +106,95 @@ class DecimalField(IntegerField):
|
||||
min_value: Optional[Any] = ...,
|
||||
max_digits: Optional[Any] = ...,
|
||||
decimal_places: Optional[Any] = ...,
|
||||
**kwargs: Any
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
def validate(self, value: Optional[Decimal]) -> None: ...
|
||||
|
||||
class BaseTemporalField(Field):
|
||||
input_formats: Any = ...
|
||||
def __init__(self, *, input_formats: Optional[Any] = ..., **kwargs: Any) -> None: ...
|
||||
def strptime(self, value: Any, format: Any) -> Any: ...
|
||||
def __init__(
|
||||
self,
|
||||
input_formats: Optional[Any] = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
def strptime(self, value: Any, format: str) -> Any: ...
|
||||
|
||||
class DateField(BaseTemporalField):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
input_formats: Any = ...
|
||||
default_error_messages: Any = ...
|
||||
def strptime(self, value: str, format: str) -> date: ...
|
||||
|
||||
class TimeField(BaseTemporalField):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
input_formats: Any = ...
|
||||
default_error_messages: Any = ...
|
||||
def strptime(self, value: str, format: str) -> time: ...
|
||||
|
||||
class DateTimeField(BaseTemporalField):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
input_formats: Any = ...
|
||||
default_error_messages: Any = ...
|
||||
def prepare_value(self, value: Optional[datetime]) -> Optional[datetime]: ...
|
||||
def strptime(self, value: str, format: str) -> datetime: ...
|
||||
class DateField(BaseTemporalField): ...
|
||||
class TimeField(BaseTemporalField): ...
|
||||
class DateTimeField(BaseTemporalField): ...
|
||||
|
||||
class DurationField(Field):
|
||||
disabled: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
default_error_messages: Any = ...
|
||||
def prepare_value(self, value: Optional[Union[timedelta, str]]) -> Optional[str]: ...
|
||||
|
||||
class RegexField(CharField):
|
||||
disabled: bool
|
||||
empty_value: str
|
||||
error_messages: Dict[str, str]
|
||||
max_length: Optional[int]
|
||||
min_length: Optional[int]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
strip: bool
|
||||
def __init__(self, regex: str, **kwargs: Any) -> None: ...
|
||||
regex: Any = ...
|
||||
regex: str = ...
|
||||
def __init__(
|
||||
self,
|
||||
regex: Union[str, Pattern],
|
||||
max_length: Optional[Any] = ...,
|
||||
min_length: Optional[Any] = ...,
|
||||
strip: bool = ...,
|
||||
empty_value: Optional[str] = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class EmailField(CharField):
|
||||
disabled: bool
|
||||
empty_value: Optional[str]
|
||||
error_messages: Dict[str, str]
|
||||
max_length: Optional[int]
|
||||
min_length: Optional[int]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
strip: bool
|
||||
default_validators: Any = ...
|
||||
def __init__(self, **kwargs: Any) -> None: ...
|
||||
class EmailField(CharField): ...
|
||||
|
||||
class FileField(Field):
|
||||
disabled: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
default_error_messages: Any = ...
|
||||
max_length: Optional[int] = ...
|
||||
allow_empty_file: bool = ...
|
||||
def __init__(self, *, max_length: Optional[Any] = ..., allow_empty_file: bool = ..., **kwargs: Any) -> None: ...
|
||||
def bound_data(self, data: Any, initial: Optional[FieldFile]) -> Optional[Union[File, str]]: ...
|
||||
def __init__(
|
||||
self,
|
||||
max_length: Optional[Any] = ...,
|
||||
allow_empty_file: bool = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
def clean(self, data: Any, initial: Optional[Any] = ...): ...
|
||||
|
||||
class ImageField(FileField):
|
||||
allow_empty_file: bool
|
||||
disabled: bool
|
||||
max_length: Optional[int]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
default_validators: Any = ...
|
||||
default_error_messages: Any = ...
|
||||
|
||||
class URLField(CharField):
|
||||
disabled: bool
|
||||
empty_value: Optional[str]
|
||||
error_messages: Dict[str, str]
|
||||
max_length: Optional[int]
|
||||
min_length: Optional[int]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
strip: bool
|
||||
default_error_messages: Any = ...
|
||||
default_validators: Any = ...
|
||||
def __init__(self, **kwargs: Any) -> None: ...
|
||||
|
||||
class BooleanField(Field):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
def validate(self, value: bool) -> None: ...
|
||||
|
||||
class NullBooleanField(BooleanField):
|
||||
disabled: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
def validate(self, value: Optional[bool]) -> None: ...
|
||||
class ImageField(FileField): ...
|
||||
class URLField(CharField): ...
|
||||
class BooleanField(Field): ...
|
||||
class NullBooleanField(BooleanField): ...
|
||||
|
||||
class CallableChoiceIterator:
|
||||
choices_func: Callable = ...
|
||||
@@ -229,125 +202,191 @@ class CallableChoiceIterator:
|
||||
def __iter__(self) -> None: ...
|
||||
|
||||
class ChoiceField(Field):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
default_error_messages: Any = ...
|
||||
choices: Any = ...
|
||||
def __init__(self, *, choices: Any = ..., **kwargs: Any) -> None: ...
|
||||
def validate(self, value: Any) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
choices: Any = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
def valid_value(self, value: str) -> bool: ...
|
||||
|
||||
class TypedChoiceField(ChoiceField):
|
||||
disabled: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
coerce: Union[Callable, Type[Union[bool, float, str]]] = ...
|
||||
coerce: Union[Callable, Type[Any]] = ...
|
||||
empty_value: Optional[str] = ...
|
||||
def __init__(self, *, coerce: Any = ..., empty_value: str = ..., **kwargs: Any) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
coerce: Any = ...,
|
||||
empty_value: Optional[str] = ...,
|
||||
choices: Any = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class MultipleChoiceField(ChoiceField):
|
||||
disabled: bool
|
||||
error_messages: Dict[str, str]
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
hidden_widget: Any = ...
|
||||
default_error_messages: Any = ...
|
||||
def validate(self, value: List[str]) -> None: ...
|
||||
class MultipleChoiceField(ChoiceField): ...
|
||||
|
||||
class TypedMultipleChoiceField(MultipleChoiceField):
|
||||
disabled: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
coerce: Union[Callable, Type[float]] = ...
|
||||
empty_value: Optional[List[Any]] = ...
|
||||
def __init__(self, *, coerce: Any = ..., **kwargs: Any) -> None: ...
|
||||
def validate(self, value: List[str]) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
coerce: Any = ...,
|
||||
empty_value: Optional[str] = ...,
|
||||
choices: Any = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class ComboField(Field):
|
||||
disabled: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
fields: Any = ...
|
||||
def __init__(self, fields: List[CharField], **kwargs: Any) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
fields: Sequence[Field],
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class MultiValueField(Field):
|
||||
disabled: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
default_error_messages: Any = ...
|
||||
require_all_fields: bool = ...
|
||||
fields: Any = ...
|
||||
def __init__(self, fields: Tuple[Field, Field], *, require_all_fields: bool = ..., **kwargs: Any) -> None: ...
|
||||
def validate(self, value: Union[datetime, str]) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
fields: Sequence[Field],
|
||||
require_all_fields: bool = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
def compress(self, data_list: Any) -> Any: ...
|
||||
|
||||
class FilePathField(ChoiceField):
|
||||
allow_files: bool
|
||||
allow_folders: bool
|
||||
disabled: bool
|
||||
match: Optional[str]
|
||||
path: str
|
||||
recursive: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
choices: Any = ...
|
||||
match_re: Any = ...
|
||||
def __init__(
|
||||
self,
|
||||
path: str,
|
||||
*,
|
||||
match: Optional[Any] = ...,
|
||||
recursive: bool = ...,
|
||||
allow_files: bool = ...,
|
||||
allow_folders: bool = ...,
|
||||
**kwargs: Any
|
||||
choices: Any = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class SplitDateTimeField(MultiValueField):
|
||||
disabled: bool
|
||||
require_all_fields: bool
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
hidden_widget: Any = ...
|
||||
default_error_messages: Any = ...
|
||||
def __init__(
|
||||
self, *, input_date_formats: Optional[Any] = ..., input_time_formats: Optional[Any] = ..., **kwargs: Any
|
||||
self,
|
||||
input_date_formats: Optional[Any] = ...,
|
||||
input_time_formats: Optional[Any] = ...,
|
||||
fields: Sequence[Field] = ...,
|
||||
require_all_fields: bool = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
def compress(self, data_list: List[Optional[datetime]]) -> Optional[datetime]: ...
|
||||
|
||||
class GenericIPAddressField(CharField):
|
||||
disabled: bool
|
||||
empty_value: str
|
||||
error_messages: Dict[str, str]
|
||||
max_length: None
|
||||
min_length: None
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
strip: bool
|
||||
unpack_ipv4: bool = ...
|
||||
default_validators: List[Callable] = ...
|
||||
def __init__(self, *, protocol: str = ..., unpack_ipv4: bool = ..., **kwargs: Any) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
protocol: str = ...,
|
||||
unpack_ipv4: bool = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class SlugField(CharField):
|
||||
disabled: bool
|
||||
empty_value: str
|
||||
max_length: Optional[int]
|
||||
min_length: None
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
strip: bool
|
||||
allow_unicode: bool = ...
|
||||
def __init__(self, *, allow_unicode: bool = ..., **kwargs: Any) -> None: ...
|
||||
def __init__(
|
||||
self,
|
||||
allow_unicode: bool = ...,
|
||||
required: bool = ...,
|
||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||
label: Optional[Any] = ...,
|
||||
initial: Optional[Any] = ...,
|
||||
help_text: str = ...,
|
||||
error_messages: Optional[Any] = ...,
|
||||
show_hidden_initial: bool = ...,
|
||||
validators: Sequence[Any] = ...,
|
||||
localize: bool = ...,
|
||||
disabled: bool = ...,
|
||||
label_suffix: Optional[Any] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class UUIDField(CharField):
|
||||
disabled: bool
|
||||
empty_value: str
|
||||
max_length: None
|
||||
min_length: None
|
||||
required: bool
|
||||
show_hidden_initial: bool
|
||||
strip: bool
|
||||
default_error_messages: Any = ...
|
||||
def prepare_value(self, value: UUID) -> str: ...
|
||||
class UUIDField(CharField): ...
|
||||
|
||||
@@ -1,48 +1,45 @@
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Iterator, List, Mapping, Optional, Tuple, Type, Union
|
||||
from typing import Any, Dict, Iterator, List, Mapping, Optional, Sequence, Type, Union
|
||||
|
||||
from django.core.exceptions import ValidationError as ValidationError
|
||||
from django.core.files.base import File
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.db.models.query import QuerySet
|
||||
from django.forms.boundfield import BoundField
|
||||
from django.forms.fields import Field
|
||||
from django.forms.renderers import BaseRenderer
|
||||
from django.forms.utils import ErrorDict, ErrorList
|
||||
from django.forms.widgets import Media, MediaDefiningClass
|
||||
from django.utils.safestring import SafeText
|
||||
|
||||
class DeclarativeFieldsMetaclass(MediaDefiningClass):
|
||||
def __new__(
|
||||
mcs: Type[DeclarativeFieldsMetaclass], name: str, bases: Tuple[Type[BaseForm]], attrs: OrderedDict
|
||||
) -> Type[BaseForm]: ...
|
||||
def __new__(mcs, name: str, bases: Sequence[Type[BaseForm]], attrs: Dict[str, Any]) -> Type[BaseForm]: ...
|
||||
|
||||
class BaseForm:
|
||||
default_renderer: Any = ...
|
||||
field_order: Any = ...
|
||||
prefix: Any = ...
|
||||
use_required_attribute: bool = ...
|
||||
is_bound: Any = ...
|
||||
data: Any = ...
|
||||
files: Any = ...
|
||||
is_bound: bool = ...
|
||||
data: Dict[str, Any] = ...
|
||||
files: Optional[Dict[str, Any]] = ...
|
||||
auto_id: Any = ...
|
||||
initial: Any = ...
|
||||
error_class: Any = ...
|
||||
label_suffix: Any = ...
|
||||
empty_permitted: Any = ...
|
||||
fields: Any = ...
|
||||
renderer: Any = ...
|
||||
initial: Dict[str, Any] = ...
|
||||
error_class: Type[ErrorList] = ...
|
||||
prefix: str = ...
|
||||
label_suffix: str = ...
|
||||
empty_permitted: bool = ...
|
||||
fields: Dict[str, Any] = ...
|
||||
renderer: BaseRenderer = ...
|
||||
def __init__(
|
||||
self,
|
||||
data: Optional[Mapping[str, Any]] = ...,
|
||||
files: Optional[Mapping[str, File]] = ...,
|
||||
files: Optional[Mapping[str, Any]] = ...,
|
||||
auto_id: Optional[Union[bool, str]] = ...,
|
||||
prefix: Optional[str] = ...,
|
||||
initial: Optional[Mapping[str, Any]] = ...,
|
||||
error_class: Type[ErrorList] = ...,
|
||||
label_suffix: None = ...,
|
||||
label_suffix: Optional[str] = ...,
|
||||
empty_permitted: bool = ...,
|
||||
field_order: None = ...,
|
||||
field_order: Optional[Any] = ...,
|
||||
use_required_attribute: Optional[bool] = ...,
|
||||
renderer: Any = ...,
|
||||
) -> None: ...
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import collections
|
||||
from typing import Any, List, Optional, Union, Dict, Type
|
||||
|
||||
from django.forms.renderers import BaseRenderer
|
||||
from django.forms.utils import ErrorList
|
||||
from typing import Any, Dict, Mapping, Optional, Sequence, Sized
|
||||
|
||||
from django.forms import Form
|
||||
|
||||
@@ -17,21 +13,9 @@ DEFAULT_MIN_NUM: int = ...
|
||||
DEFAULT_MAX_NUM: int = ...
|
||||
|
||||
class ManagementForm(Form):
|
||||
auto_id: Union[bool, str]
|
||||
cleaned_data: Dict[str, Optional[int]]
|
||||
data: Dict[str, Union[List[int], int, str]]
|
||||
empty_permitted: bool
|
||||
error_class: Type[ErrorList]
|
||||
fields: collections.OrderedDict
|
||||
files: Dict[Any, Any]
|
||||
initial: Dict[str, int]
|
||||
is_bound: bool
|
||||
label_suffix: str
|
||||
prefix: str
|
||||
renderer: BaseRenderer
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None: ...
|
||||
|
||||
class BaseFormSet:
|
||||
class BaseFormSet(Sized, Mapping[str, Any]):
|
||||
is_bound: Any = ...
|
||||
prefix: Any = ...
|
||||
auto_id: Any = ...
|
||||
@@ -57,6 +41,7 @@ class BaseFormSet:
|
||||
def management_form(self): ...
|
||||
def total_form_count(self): ...
|
||||
def initial_form_count(self): ...
|
||||
@property
|
||||
def forms(self): ...
|
||||
def get_form_kwargs(self, index: Any): ...
|
||||
@property
|
||||
@@ -101,4 +86,4 @@ def formset_factory(
|
||||
min_num: Optional[Any] = ...,
|
||||
validate_min: bool = ...,
|
||||
): ...
|
||||
def all_valid(formsets: List[Any]) -> bool: ...
|
||||
def all_valid(formsets: Sequence[Any]) -> bool: ...
|
||||
|
||||
@@ -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, Sequence
|
||||
from typing import Any, Callable, Dict, Iterator, List, MutableMapping, Optional, Sequence, Tuple, Type, Union
|
||||
from unittest.mock import MagicMock
|
||||
from uuid import UUID
|
||||
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.core.files.base import File
|
||||
from django.db import models
|
||||
from django.db.models import ForeignKey
|
||||
from django.db.models.base import Model
|
||||
from django.db.models.manager import Manager
|
||||
@@ -14,9 +15,8 @@ from django.forms.fields import CharField, ChoiceField, Field
|
||||
from django.forms.forms import BaseForm, DeclarativeFieldsMetaclass
|
||||
from django.forms.formsets import BaseFormSet
|
||||
from django.forms.utils import ErrorList
|
||||
from django.forms.widgets import Input, Widget, Select
|
||||
from django.http.request import QueryDict
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from django.forms.widgets import Input, Widget
|
||||
from typing_extensions import Literal
|
||||
|
||||
ALL_FIELDS: str
|
||||
|
||||
@@ -57,21 +57,19 @@ class ModelFormOptions:
|
||||
def __init__(self, options: Optional[type] = ...) -> None: ...
|
||||
|
||||
class ModelFormMetaclass(DeclarativeFieldsMetaclass):
|
||||
def __new__(
|
||||
mcs: Type[ModelFormMetaclass], name: str, bases: Tuple[Type[ModelForm]], attrs: OrderedDict
|
||||
) -> Type[ModelForm]: ...
|
||||
def __new__(mcs, name: str, bases: Sequence[Type[ModelForm]], attrs: Dict[str, Any]) -> Type[ModelForm]: ...
|
||||
|
||||
class BaseModelForm(BaseForm):
|
||||
instance: Any = ...
|
||||
def __init__(
|
||||
self,
|
||||
data: Optional[Union[Dict[str, Any], QueryDict]] = ...,
|
||||
files: Optional[Union[Dict[str, SimpleUploadedFile], MultiValueDict]] = ...,
|
||||
data: Optional[Dict[str, Any]] = ...,
|
||||
files: Optional[Dict[str, File]] = ...,
|
||||
auto_id: Union[bool, str] = ...,
|
||||
prefix: None = ...,
|
||||
initial: Optional[Union[Dict[str, List[int]], Dict[str, int]]] = ...,
|
||||
prefix: Optional[str] = ...,
|
||||
initial: Optional[Dict[str, Any]] = ...,
|
||||
error_class: Type[ErrorList] = ...,
|
||||
label_suffix: None = ...,
|
||||
label_suffix: Optional[str] = ...,
|
||||
empty_permitted: bool = ...,
|
||||
instance: Optional[Model] = ...,
|
||||
use_required_attribute: None = ...,
|
||||
@@ -87,16 +85,16 @@ class ModelForm(BaseModelForm): ...
|
||||
def modelform_factory(
|
||||
model: Type[Model],
|
||||
form: Type[ModelForm] = ...,
|
||||
fields: Optional[Union[List[str], str]] = ...,
|
||||
exclude: None = ...,
|
||||
formfield_callback: Optional[str] = ...,
|
||||
widgets: None = ...,
|
||||
localized_fields: None = ...,
|
||||
labels: None = ...,
|
||||
help_texts: None = ...,
|
||||
error_messages: None = ...,
|
||||
field_classes: None = ...,
|
||||
) -> Any: ...
|
||||
fields: Optional[Union[Sequence[str], Literal["__all__"]]] = ...,
|
||||
exclude: Optional[Sequence[str]] = ...,
|
||||
formfield_callback: Optional[Union[str, Callable[[models.Field], Field]]] = ...,
|
||||
widgets: Optional[MutableMapping[str, Widget]] = ...,
|
||||
localized_fields: Optional[Sequence[str]] = ...,
|
||||
labels: Optional[MutableMapping[str, str]] = ...,
|
||||
help_texts: Optional[MutableMapping[str, str]] = ...,
|
||||
error_messages: Optional[MutableMapping[str, Dict[str, Any]]] = ...,
|
||||
field_classes: Optional[MutableMapping[str, Type[Field]]] = ...,
|
||||
) -> Type[ModelForm]: ...
|
||||
|
||||
class BaseModelFormSet(BaseFormSet):
|
||||
model: Any = ...
|
||||
@@ -148,13 +146,13 @@ def modelformset_factory(
|
||||
exclude: Optional[Sequence[str]] = ...,
|
||||
widgets: Optional[Dict[str, Any]] = ...,
|
||||
validate_max: bool = ...,
|
||||
localized_fields: None = ...,
|
||||
localized_fields: Optional[Sequence[str]] = ...,
|
||||
labels: Optional[Dict[str, str]] = ...,
|
||||
help_texts: Optional[Dict[str, str]] = ...,
|
||||
error_messages: Optional[Dict[str, Dict[str, str]]] = ...,
|
||||
validate_min: bool = ...,
|
||||
field_classes: Optional[Dict[str, Any]] = ...,
|
||||
) -> Any: ...
|
||||
field_classes: Optional[Dict[str, Type[Field]]] = ...,
|
||||
) -> Type[BaseModelFormSet]: ...
|
||||
|
||||
class BaseInlineFormSet(BaseModelFormSet):
|
||||
instance: Any = ...
|
||||
@@ -192,14 +190,14 @@ def inlineformset_factory(
|
||||
formfield_callback: Optional[Callable] = ...,
|
||||
widgets: Optional[Dict[str, Any]] = ...,
|
||||
validate_max: bool = ...,
|
||||
localized_fields: None = ...,
|
||||
localized_fields: Optional[Sequence[str]] = ...,
|
||||
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: Optional[Dict[str, Any]] = ...,
|
||||
) -> Any: ...
|
||||
) -> Type[BaseInlineFormSet]: ...
|
||||
|
||||
class InlineForeignKeyField(Field):
|
||||
disabled: bool
|
||||
|
||||
@@ -6,11 +6,11 @@ from django.core.exceptions import ValidationError
|
||||
from django.utils.safestring import SafeText
|
||||
|
||||
def pretty_name(name: str) -> str: ...
|
||||
def flatatt(attrs: Dict[str, Optional[str]]) -> SafeText: ...
|
||||
def flatatt(attrs: Dict[str, Any]) -> SafeText: ...
|
||||
|
||||
class ErrorDict(dict):
|
||||
def as_data(self) -> Dict[str, List[ValidationError]]: ...
|
||||
def get_json_data(self, escape_html: bool = ...) -> Dict[str, List[Dict[str, str]]]: ...
|
||||
def get_json_data(self, escape_html: bool = ...) -> Dict[str, Any]: ...
|
||||
def as_json(self, escape_html: bool = ...) -> str: ...
|
||||
def as_ul(self) -> str: ...
|
||||
def as_text(self) -> str: ...
|
||||
@@ -19,7 +19,9 @@ class ErrorList(UserList):
|
||||
data: List[Union[ValidationError, str]]
|
||||
error_class: str = ...
|
||||
def __init__(
|
||||
self, initlist: Optional[Union[ErrorList, Sequence[str]]] = ..., error_class: Optional[str] = ...
|
||||
self,
|
||||
initlist: Optional[Union[ErrorList, Sequence[Union[str, Exception]]]] = ...,
|
||||
error_class: Optional[str] = ...,
|
||||
) -> None: ...
|
||||
def as_data(self) -> List[ValidationError]: ...
|
||||
def get_json_data(self, escape_html: bool = ...) -> List[Dict[str, str]]: ...
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
from datetime import time
|
||||
from decimal import Decimal
|
||||
from itertools import chain
|
||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Set, Tuple, Type, Union, Iterable, Sequence
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Set, Tuple, Type, Union
|
||||
|
||||
from django.contrib.admin.options import BaseModelAdmin
|
||||
from django.core.files.base import File
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.db.models.fields.files import FieldFile
|
||||
from django.forms.forms import BaseForm
|
||||
from django.forms.renderers import EngineMixin
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from django.utils.safestring import SafeText
|
||||
|
||||
_OptAttrs = Dict[str, str]
|
||||
|
||||
class MediaOrderConflictWarning(RuntimeWarning): ...
|
||||
|
||||
class Media:
|
||||
@@ -32,9 +31,7 @@ class Media:
|
||||
def __add__(self, other: Media) -> Media: ...
|
||||
|
||||
class MediaDefiningClass(type):
|
||||
def __new__(
|
||||
mcs: Type[MediaDefiningClass], name: str, bases: Tuple, attrs: Any
|
||||
) -> Type[Union[BaseModelAdmin, BaseForm, Widget]]: ...
|
||||
def __new__(mcs, name: str, bases: Sequence[Any], attrs: Dict[str, Any]) -> type: ...
|
||||
|
||||
class Widget:
|
||||
needs_multipart_form: bool = ...
|
||||
@@ -61,10 +58,10 @@ class Widget:
|
||||
self, base_attrs: Dict[str, Union[float, str]], extra_attrs: Optional[Dict[str, Union[bool, str]]] = ...
|
||||
) -> Dict[str, Union[Decimal, float, str]]: ...
|
||||
def value_from_datadict(
|
||||
self, data: dict, files: Union[Dict[str, SimpleUploadedFile], MultiValueDict], name: str
|
||||
self, data: dict, files: Union[Dict[str, Iterable[Any]], MultiValueDict], name: str
|
||||
) -> Any: ...
|
||||
def value_omitted_from_data(
|
||||
self, data: Dict[str, Any], files: Union[Dict[str, SimpleUploadedFile], MultiValueDict], name: str
|
||||
self, data: Dict[str, Any], files: Union[Dict[str, Iterable[Any]], MultiValueDict], name: str
|
||||
) -> bool: ...
|
||||
def id_for_label(self, id_: str) -> str: ...
|
||||
def use_required_attribute(self, initial: Any) -> bool: ...
|
||||
@@ -80,6 +77,7 @@ class URLInput(Input): ...
|
||||
|
||||
class PasswordInput(Input):
|
||||
render_value: bool = ...
|
||||
def __init__(self, attrs: Optional[_OptAttrs] = ..., render_value: bool = ...): ...
|
||||
|
||||
class HiddenInput(Input):
|
||||
choices: Iterable[Tuple[str, str]]
|
||||
@@ -105,6 +103,7 @@ class DateTimeBaseInput(TextInput):
|
||||
format_key: str = ...
|
||||
supports_microseconds: bool = ...
|
||||
format: Optional[str] = ...
|
||||
def __init__(self, attrs: Optional[_OptAttrs] = ..., format: Optional[str] = ...): ...
|
||||
|
||||
class DateInput(DateTimeBaseInput): ...
|
||||
class DateTimeInput(DateTimeBaseInput): ...
|
||||
@@ -112,9 +111,7 @@ class TimeInput(DateTimeBaseInput): ...
|
||||
|
||||
class CheckboxInput(Input):
|
||||
check_test: Callable = ...
|
||||
def __init__(self, attrs: Optional[Dict[str, str]] = ..., check_test: Optional[Callable] = ...) -> None: ...
|
||||
|
||||
_OptAttrs = Dict[str, Any]
|
||||
def __init__(self, attrs: Optional[_OptAttrs] = ..., check_test: Optional[Callable] = ...) -> None: ...
|
||||
|
||||
class ChoiceWidget(Widget):
|
||||
allow_multiple_selected: bool = ...
|
||||
@@ -165,7 +162,7 @@ class CheckboxSelectMultiple(ChoiceWidget):
|
||||
class MultiWidget(Widget):
|
||||
template_name: str = ...
|
||||
widgets: List[Widget] = ...
|
||||
def __init__(self, widgets: Sequence[Widget], attrs: Optional[_OptAttrs] = ...) -> None: ...
|
||||
def __init__(self, widgets: Sequence[Union[Widget, Type[Widget]]], attrs: Optional[_OptAttrs] = ...) -> None: ...
|
||||
@property
|
||||
def is_hidden(self) -> bool: ...
|
||||
def decompress(self, value: Any) -> Optional[Any]: ...
|
||||
@@ -209,7 +206,7 @@ class SelectDateWidget(Widget):
|
||||
def __init__(
|
||||
self,
|
||||
attrs: Optional[_OptAttrs] = ...,
|
||||
years: Optional[Union[Tuple[Union[int, str]], range]] = ...,
|
||||
months: None = ...,
|
||||
empty_label: Optional[Union[Tuple[str, str], str]] = ...,
|
||||
years: Optional[Iterable[Union[int, str]]] = ...,
|
||||
months: Optional[Dict[int, str]] = ...,
|
||||
empty_label: Optional[Union[str, Sequence[str]]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
@@ -33,7 +33,7 @@ class HttpResponseBase(Iterable[AnyStr]):
|
||||
def has_header(self, header: str) -> bool: ...
|
||||
def items(self) -> Iterable[Tuple[str, str]]: ...
|
||||
@overload
|
||||
def get(self, header: Union[str, bytes], alternate: str) -> str: ...
|
||||
def get(self, header: Union[str, bytes], alternate: Optional[str]) -> str: ...
|
||||
@overload
|
||||
def get(self, header: Union[str, bytes]) -> Optional[str]: ...
|
||||
def set_cookie(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Type, Union
|
||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Type, Union, Iterable
|
||||
|
||||
from django.http.request import HttpRequest
|
||||
from django.template.base import Node, Origin, Template
|
||||
@@ -15,10 +15,10 @@ class ContextDict(dict):
|
||||
def __enter__(self) -> ContextDict: ...
|
||||
def __exit__(self, *args: Any, **kwargs: Any) -> None: ...
|
||||
|
||||
class BaseContext:
|
||||
class BaseContext(Iterable[Any]):
|
||||
def __init__(self, dict_: Any = ...) -> None: ...
|
||||
def __copy__(self) -> BaseContext: ...
|
||||
def __iter__(self) -> None: ...
|
||||
def __iter__(self) -> Iterator[Any]: ...
|
||||
def push(self, *args: Any, **kwargs: Any) -> ContextDict: ...
|
||||
def pop(self) -> ContextDict: ...
|
||||
def __setitem__(self, key: Union[Node, str], value: Any) -> None: ...
|
||||
@@ -50,7 +50,6 @@ class Context(BaseContext):
|
||||
class RenderContext(BaseContext):
|
||||
dicts: List[Dict[Union[IncludeNode, str], str]]
|
||||
template: Optional[Template] = ...
|
||||
def __iter__(self) -> None: ...
|
||||
def push_state(self, template: Template, isolated_context: bool = ...) -> Iterator[None]: ...
|
||||
|
||||
class RequestContext(Context):
|
||||
|
||||
@@ -1,48 +1,44 @@
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Type
|
||||
from typing import Any, Callable, Dict, List, Optional, Type
|
||||
|
||||
from django import http
|
||||
|
||||
logger = ... # type: Any
|
||||
|
||||
class ContextMixin:
|
||||
def get_context_data(self, **kwargs: object) -> Dict[str, Any]: ...
|
||||
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]: ...
|
||||
|
||||
class View:
|
||||
http_method_names = ... # type: List[str]
|
||||
request = ... # type: http.HttpRequest
|
||||
args = ... # type: Tuple[object, ...]
|
||||
kwargs = ... # type: Dict[str, object]
|
||||
def __init__(self, **kwargs: object) -> None: ...
|
||||
http_method_names: List[str] = ...
|
||||
request: http.HttpRequest = ...
|
||||
args: Any = ...
|
||||
kwargs: Any = ...
|
||||
def __init__(self, **kwargs: Any) -> None: ...
|
||||
@classmethod
|
||||
def as_view(cls: Any, **initkwargs: object) -> Callable[..., http.HttpResponse]: ...
|
||||
def dispatch(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def http_method_not_allowed(
|
||||
self, request: http.HttpRequest, *args: object, **kwargs: object
|
||||
) -> http.HttpResponse: ...
|
||||
def options(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def as_view(cls: Any, **initkwargs: Any) -> Callable[..., http.HttpResponse]: ...
|
||||
def dispatch(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
def http_method_not_allowed(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
def options(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
|
||||
class TemplateResponseMixin:
|
||||
template_name = ... # type: str
|
||||
template_engine = ... # type: Optional[str]
|
||||
response_class = ... # type: Type[http.HttpResponse]
|
||||
content_type = ... # type: Optional[str]
|
||||
request = ... # type: http.HttpRequest
|
||||
def render_to_response(self, context: Dict[str, object], **response_kwargs: object) -> http.HttpResponse: ...
|
||||
template_name: str = ...
|
||||
template_engine: Optional[str] = ...
|
||||
response_class: Type[http.HttpResponse] = ...
|
||||
content_type: Optional[str] = ...
|
||||
request: http.HttpRequest = ...
|
||||
def render_to_response(self, context: Dict[str, Any], **response_kwargs: Any) -> http.HttpResponse: ...
|
||||
def get_template_names(self) -> List[str]: ...
|
||||
|
||||
class TemplateView(TemplateResponseMixin, ContextMixin, View):
|
||||
def get(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def get(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
|
||||
class RedirectView(View):
|
||||
permanent = ... # type: bool
|
||||
url = ... # type: Optional[str]
|
||||
pattern_name = ... # type: Optional[str]
|
||||
query_string = ... # type: bool
|
||||
def get_redirect_url(self, *args: object, **kwargs: object) -> Optional[str]: ...
|
||||
def get(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def head(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def post(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def options(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def delete(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def put(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
def patch(self, request: http.HttpRequest, *args: object, **kwargs: object) -> http.HttpResponse: ...
|
||||
permanent: bool = ...
|
||||
url: Optional[str] = ...
|
||||
pattern_name: Optional[str] = ...
|
||||
query_string: bool = ...
|
||||
def get_redirect_url(self, *args: Any, **kwargs: Any) -> Optional[str]: ...
|
||||
def get(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
def head(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
def post(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
def options(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
def delete(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
def put(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
def patch(self, request: http.HttpRequest, *args: Any, **kwargs: Any) -> http.HttpResponse: ...
|
||||
|
||||
@@ -5,31 +5,30 @@ from django.http import HttpResponse, HttpRequest
|
||||
from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
|
||||
|
||||
class SingleObjectMixin(ContextMixin):
|
||||
model = ... # type: Optional[Type[models.Model]]
|
||||
queryset = ... # type: Optional[models.query.QuerySet]
|
||||
slug_field = ... # type: str
|
||||
context_object_name = ... # type: Optional[str]
|
||||
slug_url_kwarg = ... # type: str
|
||||
pk_url_kwarg = ... # type: str
|
||||
query_pk_and_slug = ... # type: bool
|
||||
object = ... # type: models.Model
|
||||
kwargs = ... # type: Dict[str, object]
|
||||
def get_object(self, queryset: models.query.QuerySet = None) -> models.Model: ...
|
||||
model: Optional[Type[models.Model]] = ...
|
||||
queryset: Optional[models.query.QuerySet] = ...
|
||||
slug_field: str = ...
|
||||
context_object_name: Optional[str] = ...
|
||||
slug_url_kwarg: str = ...
|
||||
pk_url_kwarg: str = ...
|
||||
query_pk_and_slug: bool = ...
|
||||
object: models.Model = ...
|
||||
kwargs: Dict[str, Any] = ...
|
||||
def get_object(self, queryset: Optional[models.query.QuerySet] = None) -> models.Model: ...
|
||||
def get_queryset(self) -> models.query.QuerySet: ...
|
||||
def get_slug_field(self) -> str: ...
|
||||
def get_context_object_name(self, obj: Any) -> Optional[str]: ...
|
||||
def get_context_data(self, **kwargs: object) -> Dict[str, Any]: ...
|
||||
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]: ...
|
||||
|
||||
class BaseDetailView(SingleObjectMixin, View):
|
||||
def render_to_response(self, context: Dict[str, object], **response_kwargs: object) -> HttpResponse: ...
|
||||
object = ... # type: models.Model
|
||||
def get(self, request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: ...
|
||||
def render_to_response(self, context: Dict[str, Any], **response_kwargs: Any) -> HttpResponse: ...
|
||||
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: ...
|
||||
|
||||
class SingleObjectTemplateResponseMixin(TemplateResponseMixin):
|
||||
template_name_field = ... # type: Optional[str]
|
||||
template_name_suffix = ... # type: str
|
||||
model = ... # type: Optional[Type[models.Model]]
|
||||
object = ... # type: models.Model
|
||||
template_name_field: Optional[str] = ...
|
||||
template_name_suffix: str = ...
|
||||
model: Optional[Type[models.Model]] = ...
|
||||
object: models.Model = ...
|
||||
def get_template_names(self) -> List[str]: ...
|
||||
|
||||
class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView): ...
|
||||
|
||||
@@ -1,77 +1,53 @@
|
||||
from typing import Any, Callable, Dict, Optional, Sequence, Type, Union
|
||||
|
||||
from django.db import models
|
||||
from django.forms.forms import BaseForm
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
|
||||
from django.views.generic.detail import BaseDetailView, SingleObjectMixin, SingleObjectTemplateResponseMixin
|
||||
from typing_extensions import Literal
|
||||
|
||||
from django.db import models
|
||||
from django.forms import Form
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
|
||||
class FormMixin(ContextMixin):
|
||||
initial: Dict[str, Any] = ...
|
||||
form_class: Optional[Type[Form]] = ...
|
||||
form_class: Optional[Type[BaseForm]] = ...
|
||||
success_url: Optional[Union[str, Callable[..., Any]]] = ...
|
||||
prefix: Optional[str] = ...
|
||||
request: HttpRequest = ...
|
||||
def render_to_response(self, context: Dict[str, Any], **response_kwargs: object) -> HttpResponse: ...
|
||||
def get_initial(self) -> Dict[str, Any]: ...
|
||||
def get_prefix(self) -> Optional[str]: ...
|
||||
def get_form_class(self) -> Type[Form]: ...
|
||||
def get_form(self, form_class: Type[Form] = None) -> Form: ...
|
||||
def get_form_class(self) -> Type[BaseForm]: ...
|
||||
def get_form(self, form_class: Optional[Type[BaseForm]] = None) -> BaseForm: ...
|
||||
def get_form_kwargs(self) -> Dict[str, Any]: ...
|
||||
def get_success_url(self) -> str: ...
|
||||
def form_valid(self, form: Form) -> HttpResponse: ...
|
||||
def form_invalid(self, form: Form) -> HttpResponse: ...
|
||||
def get_context_data(self, **kwargs: object) -> Dict[str, Any]: ...
|
||||
def form_valid(self, form: BaseForm) -> HttpResponse: ...
|
||||
def form_invalid(self, form: BaseForm) -> HttpResponse: ...
|
||||
|
||||
class ModelFormMixin(FormMixin, SingleObjectMixin):
|
||||
fields: Optional[Union[Sequence[str], Literal["__all__"]]] = ...
|
||||
object: models.Model = ...
|
||||
def get_form_class(self) -> Type[Form]: ...
|
||||
def get_form_kwargs(self) -> Dict[str, object]: ...
|
||||
def get_success_url(self) -> str: ...
|
||||
def form_valid(self, form: Form) -> HttpResponse: ...
|
||||
|
||||
class ProcessFormView(View):
|
||||
def render_to_response(self, context: Dict[str, object], **response_kwargs: object) -> HttpResponse: ...
|
||||
def get_context_data(self, **kwargs: object) -> Dict[str, Any]: ...
|
||||
def get_form(self, form_class: Type[Form] = None) -> Form: ...
|
||||
def form_valid(self, form: Form) -> HttpResponse: ...
|
||||
def form_invalid(self, form: Form) -> HttpResponse: ...
|
||||
def get(self, request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: ...
|
||||
def post(self, request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: ...
|
||||
def put(self, *args: Any, **kwargs: Any) -> HttpResponse: ...
|
||||
def render_to_response(self, context: Dict[str, Any], **response_kwargs: Any) -> HttpResponse: ...
|
||||
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]: ...
|
||||
def get(self, request: HttpRequest, *args: str, **kwargs: Any) -> HttpResponse: ...
|
||||
def post(self, request: HttpRequest, *args: str, **kwargs: Any) -> HttpResponse: ...
|
||||
def put(self, *args: str, **kwargs: Any) -> HttpResponse: ...
|
||||
|
||||
class BaseFormView(FormMixin, ProcessFormView): ...
|
||||
class FormView(TemplateResponseMixin, BaseFormView): ...
|
||||
|
||||
class BaseCreateView(ModelFormMixin, ProcessFormView):
|
||||
object = ... # type: models.Model
|
||||
def get(self, request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: ...
|
||||
def post(self, request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: ...
|
||||
|
||||
class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView):
|
||||
template_name_suffix = ... # type: str
|
||||
|
||||
class BaseUpdateView(ModelFormMixin, ProcessFormView):
|
||||
object = ... # type: models.Model
|
||||
def get(self, request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: ...
|
||||
def post(self, request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: ...
|
||||
|
||||
class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView):
|
||||
template_name_suffix = ... # type: str
|
||||
class BaseCreateView(ModelFormMixin, ProcessFormView): ...
|
||||
class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView): ...
|
||||
class BaseUpdateView(ModelFormMixin, ProcessFormView): ...
|
||||
class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView): ...
|
||||
|
||||
_object = object
|
||||
|
||||
class DeletionMixin:
|
||||
success_url = ... # type: Optional[str]
|
||||
object = ... # type: models.Model
|
||||
def delete(self, request: HttpRequest, *args: _object, **kwargs: _object) -> HttpResponse: ...
|
||||
def post(self, request: HttpRequest, *args: _object, **kwargs: _object) -> HttpResponse: ...
|
||||
success_url: Optional[str] = ...
|
||||
object: models.Model = ...
|
||||
def post(self, request: HttpRequest, *args: str, **kwargs: Any) -> HttpResponse: ...
|
||||
def delete(self, request: HttpRequest, *args: str, **kwargs: Any) -> HttpResponse: ...
|
||||
def get_success_url(self) -> str: ...
|
||||
|
||||
class BaseDeleteView(DeletionMixin, BaseDetailView): ...
|
||||
|
||||
class DeleteView(SingleObjectTemplateResponseMixin, BaseDeleteView):
|
||||
template_name_suffix = ... # type: str
|
||||
class DeleteView(SingleObjectTemplateResponseMixin, BaseDeleteView): ...
|
||||
|
||||
@@ -2,13 +2,16 @@ import typing
|
||||
from typing import Dict, Optional
|
||||
|
||||
from mypy.checker import TypeChecker
|
||||
from mypy.nodes import AssignmentStmt, ClassDef, Expression, FuncDef, ImportedName, Lvalue, MypyFile, NameExpr, SymbolNode, \
|
||||
from mypy.nodes import AssignmentStmt, ClassDef, Expression, ImportedName, Lvalue, MypyFile, NameExpr, SymbolNode, \
|
||||
TypeInfo
|
||||
from mypy.plugin import FunctionContext
|
||||
from mypy.types import AnyType, CallableType, Instance, Type, TypeOfAny, TypeVarType, UnionType
|
||||
from mypy.types import AnyType, Instance, NoneTyp, Type, TypeOfAny, TypeVarType, UnionType
|
||||
|
||||
MODEL_CLASS_FULLNAME = 'django.db.models.base.Model'
|
||||
FIELD_FULLNAME = 'django.db.models.fields.Field'
|
||||
CHAR_FIELD_FULLNAME = 'django.db.models.fields.CharField'
|
||||
ARRAY_FIELD_FULLNAME = 'django.contrib.postgres.fields.array.ArrayField'
|
||||
AUTO_FIELD_FULLNAME = 'django.db.models.fields.AutoField'
|
||||
GENERIC_FOREIGN_KEY_FULLNAME = 'django.contrib.contenttypes.fields.GenericForeignKey'
|
||||
FOREIGN_KEY_FULLNAME = 'django.db.models.fields.related.ForeignKey'
|
||||
ONETOONE_FIELD_FULLNAME = 'django.db.models.fields.related.OneToOneField'
|
||||
@@ -19,6 +22,7 @@ QUERYSET_CLASS_FULLNAME = 'django.db.models.query.QuerySet'
|
||||
BASE_MANAGER_CLASS_FULLNAME = 'django.db.models.manager.BaseManager'
|
||||
MANAGER_CLASS_FULLNAME = 'django.db.models.manager.Manager'
|
||||
RELATED_MANAGER_CLASS_FULLNAME = 'django.db.models.manager.RelatedManager'
|
||||
MODELFORM_CLASS_FULLNAME = 'django.forms.models.ModelForm'
|
||||
|
||||
MANAGER_CLASSES = {
|
||||
MANAGER_CLASS_FULLNAME,
|
||||
@@ -51,9 +55,9 @@ def get_model_fullname(app_name: str, model_name: str,
|
||||
return None
|
||||
|
||||
|
||||
class InvalidModelString(ValueError):
|
||||
def __init__(self, model_string: str):
|
||||
self.model_string = model_string
|
||||
class SameFileModel(Exception):
|
||||
def __init__(self, model_cls_name: str):
|
||||
self.model_cls_name = model_cls_name
|
||||
|
||||
|
||||
class SelfReference(ValueError):
|
||||
@@ -66,7 +70,7 @@ def get_model_fullname_from_string(model_string: str,
|
||||
raise SelfReference()
|
||||
|
||||
if '.' not in model_string:
|
||||
raise InvalidModelString(model_string)
|
||||
raise SameFileModel(model_string)
|
||||
|
||||
app_name, model_name = model_string.split('.')
|
||||
return get_model_fullname(app_name, model_name, all_modules)
|
||||
@@ -95,12 +99,13 @@ def parse_bool(expr: Expression) -> Optional[bool]:
|
||||
return None
|
||||
|
||||
|
||||
def reparametrize_with(instance: Instance, new_typevars: typing.List[Type]):
|
||||
return Instance(instance.type, args=new_typevars)
|
||||
def reparametrize_instance(instance: Instance, new_args: typing.List[Type]) -> Instance:
|
||||
return Instance(instance.type, args=new_args,
|
||||
line=instance.line, column=instance.column)
|
||||
|
||||
|
||||
def fill_typevars_with_any(instance: Instance) -> Type:
|
||||
return reparametrize_with(instance, [AnyType(TypeOfAny.unannotated)])
|
||||
def fill_typevars_with_any(instance: Instance) -> Instance:
|
||||
return reparametrize_instance(instance, [AnyType(TypeOfAny.unannotated)])
|
||||
|
||||
|
||||
def extract_typevar_value(tp: Instance, typevar_name: str) -> Type:
|
||||
@@ -117,7 +122,7 @@ def fill_typevars(tp: Instance, type_to_fill: Instance) -> Instance:
|
||||
for typevar_arg in type_to_fill.args:
|
||||
if isinstance(typevar_arg, TypeVarType):
|
||||
typevar_values.append(extract_typevar_value(tp, typevar_arg.name))
|
||||
return reparametrize_with(type_to_fill, typevar_values)
|
||||
return Instance(type_to_fill.type, typevar_values)
|
||||
|
||||
|
||||
def get_argument_by_name(ctx: FunctionContext, name: str) -> Optional[Expression]:
|
||||
@@ -189,28 +194,12 @@ def iter_over_assignments(
|
||||
|
||||
|
||||
def extract_field_setter_type(tp: Instance) -> Optional[Type]:
|
||||
if not isinstance(tp, Instance):
|
||||
return None
|
||||
""" Extract __set__ value of a field. """
|
||||
if tp.type.has_base(FIELD_FULLNAME):
|
||||
set_method = tp.type.get_method('__set__')
|
||||
if isinstance(set_method, FuncDef) and isinstance(set_method.type, CallableType):
|
||||
if 'value' in set_method.type.arg_names:
|
||||
set_value_type = set_method.type.arg_types[set_method.type.arg_names.index('value')]
|
||||
if isinstance(set_value_type, Instance):
|
||||
set_value_type = fill_typevars(tp, set_value_type)
|
||||
return set_value_type
|
||||
elif isinstance(set_value_type, UnionType):
|
||||
items_no_typevars = []
|
||||
for item in set_value_type.items:
|
||||
if isinstance(item, Instance):
|
||||
item = fill_typevars(tp, item)
|
||||
items_no_typevars.append(item)
|
||||
return UnionType(items_no_typevars)
|
||||
|
||||
field_getter_type = extract_field_getter_type(tp)
|
||||
if field_getter_type:
|
||||
return field_getter_type
|
||||
|
||||
return tp.args[0]
|
||||
# GenericForeignKey
|
||||
if tp.type.has_base(GENERIC_FOREIGN_KEY_FULLNAME):
|
||||
return AnyType(TypeOfAny.special_form)
|
||||
return None
|
||||
|
||||
|
||||
@@ -218,9 +207,7 @@ def extract_field_getter_type(tp: Instance) -> Optional[Type]:
|
||||
if not isinstance(tp, Instance):
|
||||
return None
|
||||
if tp.type.has_base(FIELD_FULLNAME):
|
||||
get_method = tp.type.get_method('__get__')
|
||||
if isinstance(get_method, FuncDef) and isinstance(get_method.type, CallableType):
|
||||
return get_method.type.ret_type
|
||||
return tp.args[1]
|
||||
# GenericForeignKey
|
||||
if tp.type.has_base(GENERIC_FOREIGN_KEY_FULLNAME):
|
||||
return AnyType(TypeOfAny.special_form)
|
||||
@@ -240,7 +227,10 @@ def get_fields_metadata(model: TypeInfo) -> Dict[str, typing.Any]:
|
||||
return get_django_metadata(model).setdefault('fields', {})
|
||||
|
||||
|
||||
def extract_primary_key_type_for_set(model: TypeInfo) -> Optional[Type]:
|
||||
def extract_explicit_set_type_of_model_primary_key(model: TypeInfo) -> Optional[Type]:
|
||||
"""
|
||||
If field with primary_key=True is set on the model, extract its __set__ type.
|
||||
"""
|
||||
for field_name, props in get_fields_metadata(model).items():
|
||||
is_primary_key = props.get('primary_key', False)
|
||||
if is_primary_key:
|
||||
@@ -254,3 +244,40 @@ def extract_primary_key_type_for_get(model: TypeInfo) -> Optional[Type]:
|
||||
if is_primary_key:
|
||||
return extract_field_getter_type(model.names[field_name].type)
|
||||
return None
|
||||
|
||||
|
||||
def make_optional(typ: Type):
|
||||
return UnionType.make_union([typ, NoneTyp()])
|
||||
|
||||
|
||||
def make_required(typ: Type) -> Type:
|
||||
if not isinstance(typ, UnionType):
|
||||
return typ
|
||||
items = [item for item in typ.items if not isinstance(item, NoneTyp)]
|
||||
# will reduce to Instance, if only one item
|
||||
return UnionType.make_union(items)
|
||||
|
||||
|
||||
def is_optional(typ: Type) -> bool:
|
||||
if not isinstance(typ, UnionType):
|
||||
return False
|
||||
|
||||
return any([isinstance(item, NoneTyp) for item in typ.items])
|
||||
|
||||
|
||||
def has_any_of_bases(info: TypeInfo, bases: typing.Sequence[str]) -> bool:
|
||||
for base_fullname in bases:
|
||||
if info.has_base(base_fullname):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_none_expr(expr: Expression) -> bool:
|
||||
return isinstance(expr, NameExpr) and expr.fullname == 'builtins.None'
|
||||
|
||||
|
||||
def get_nested_meta_node_for_current_class(info: TypeInfo) -> Optional[TypeInfo]:
|
||||
metaclass_sym = info.names.get('Meta')
|
||||
if metaclass_sym is not None and isinstance(metaclass_sym.node, TypeInfo):
|
||||
return metaclass_sym.node
|
||||
return None
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import os
|
||||
from typing import Callable, Dict, Optional, cast
|
||||
from typing import Callable, Dict, Optional, Union, cast
|
||||
|
||||
from mypy.checker import TypeChecker
|
||||
from mypy.nodes import MemberExpr, TypeInfo
|
||||
from mypy.options import Options
|
||||
from mypy.plugin import AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin
|
||||
from mypy.types import AnyType, Instance, Type, TypeOfAny, TypeType
|
||||
from mypy.types import AnyType, Instance, Type, TypeOfAny, TypeType, UnionType
|
||||
|
||||
from mypy_django_plugin import helpers, monkeypatch
|
||||
from mypy_django_plugin.config import Config
|
||||
from mypy_django_plugin.plugins import init_create
|
||||
from mypy_django_plugin.plugins.fields import determine_type_of_array_field, record_field_properties_into_outer_model_class
|
||||
from mypy_django_plugin.plugins.migrations import determine_model_cls_from_string_for_migrations, get_string_value_from_expr
|
||||
from mypy_django_plugin.plugins.models import process_model_class
|
||||
from mypy_django_plugin.plugins.related_fields import extract_to_parameter_as_get_ret_type_for_related_field, reparametrize_with
|
||||
from mypy_django_plugin.plugins.settings import AddSettingValuesToDjangoConfObject, get_settings_metadata
|
||||
from mypy_django_plugin.transformers import fields, init_create
|
||||
from mypy_django_plugin.transformers.forms import make_meta_nested_class_inherit_from_any
|
||||
from mypy_django_plugin.transformers.migrations import determine_model_cls_from_string_for_migrations, \
|
||||
get_string_value_from_expr
|
||||
from mypy_django_plugin.transformers.models import process_model_class
|
||||
from mypy_django_plugin.transformers.settings import AddSettingValuesToDjangoConfObject, get_settings_metadata
|
||||
|
||||
|
||||
def transform_model_class(ctx: ClassDefContext) -> None:
|
||||
@@ -34,6 +35,14 @@ def transform_manager_class(ctx: ClassDefContext) -> None:
|
||||
sym.node.metadata['django']['manager_bases'][ctx.cls.fullname] = 1
|
||||
|
||||
|
||||
def transform_modelform_class(ctx: ClassDefContext) -> None:
|
||||
sym = ctx.api.lookup_fully_qualified_or_none(helpers.MODELFORM_CLASS_FULLNAME)
|
||||
if sym is not None and isinstance(sym.node, TypeInfo):
|
||||
sym.node.metadata['django']['modelform_bases'][ctx.cls.fullname] = 1
|
||||
|
||||
make_meta_nested_class_inherit_from_any(ctx)
|
||||
|
||||
|
||||
def determine_proper_manager_type(ctx: FunctionContext) -> Type:
|
||||
api = cast(TypeChecker, ctx.api)
|
||||
ret = ctx.default_return_type
|
||||
@@ -50,7 +59,7 @@ def determine_proper_manager_type(ctx: FunctionContext) -> Type:
|
||||
if base.type.fullname() in {helpers.MANAGER_CLASS_FULLNAME,
|
||||
helpers.RELATED_MANAGER_CLASS_FULLNAME,
|
||||
helpers.BASE_MANAGER_CLASS_FULLNAME}:
|
||||
ret.type.bases[i] = reparametrize_with(base, [Instance(outer_model_info, [])])
|
||||
ret.type.bases[i] = Instance(base.type, [Instance(outer_model_info, [])])
|
||||
return ret
|
||||
return ret
|
||||
|
||||
@@ -84,6 +93,17 @@ def return_user_model_hook(ctx: FunctionContext) -> Type:
|
||||
return TypeType(Instance(model_info, []))
|
||||
|
||||
|
||||
def _extract_referred_to_type_info(typ: Union[UnionType, Instance]) -> Optional[TypeInfo]:
|
||||
if isinstance(typ, Instance):
|
||||
return typ.type
|
||||
else:
|
||||
# should be Union[TYPE, None]
|
||||
typ = helpers.make_required(typ)
|
||||
if isinstance(typ, Instance):
|
||||
return typ.type
|
||||
return None
|
||||
|
||||
|
||||
def extract_and_return_primary_key_of_bound_related_field_parameter(ctx: AttributeContext) -> Type:
|
||||
if not isinstance(ctx.default_attr_type, Instance) or not (ctx.default_attr_type.type.fullname() == 'builtins.int'):
|
||||
return ctx.default_attr_type
|
||||
@@ -94,14 +114,28 @@ def extract_and_return_primary_key_of_bound_related_field_parameter(ctx: Attribu
|
||||
field_name = ctx.context.name.split('_')[0]
|
||||
sym = ctx.type.type.get(field_name)
|
||||
if sym and isinstance(sym.type, Instance) and len(sym.type.args) > 0:
|
||||
to_arg = sym.type.args[0]
|
||||
if isinstance(to_arg, AnyType):
|
||||
return AnyType(TypeOfAny.special_form)
|
||||
referred_to = sym.type.args[1]
|
||||
if isinstance(referred_to, AnyType):
|
||||
return AnyType(TypeOfAny.implementation_artifact)
|
||||
|
||||
model_type = _extract_referred_to_type_info(referred_to)
|
||||
if model_type is None:
|
||||
return AnyType(TypeOfAny.implementation_artifact)
|
||||
|
||||
model_type: TypeInfo = to_arg.type
|
||||
primary_key_type = helpers.extract_primary_key_type_for_get(model_type)
|
||||
if primary_key_type:
|
||||
return primary_key_type
|
||||
|
||||
is_nullable = helpers.get_fields_metadata(ctx.type.type).get(field_name, {}).get('null', False)
|
||||
if is_nullable:
|
||||
return helpers.make_optional(ctx.default_attr_type)
|
||||
|
||||
return ctx.default_attr_type
|
||||
|
||||
|
||||
def return_integer_type_for_id_for_non_defined_primary_key_in_models(ctx: AttributeContext) -> Type:
|
||||
if isinstance(ctx.type, Instance) and ctx.type.type.has_base(helpers.MODEL_CLASS_FULLNAME):
|
||||
return ctx.api.named_generic_type('builtins.int', [])
|
||||
return ctx.default_attr_type
|
||||
|
||||
|
||||
@@ -152,22 +186,27 @@ class DjangoPlugin(Plugin):
|
||||
def _get_current_model_bases(self) -> Dict[str, int]:
|
||||
model_sym = self.lookup_fully_qualified(helpers.MODEL_CLASS_FULLNAME)
|
||||
if model_sym is not None and isinstance(model_sym.node, TypeInfo):
|
||||
if 'django' not in model_sym.node.metadata:
|
||||
model_sym.node.metadata['django'] = {
|
||||
'model_bases': {helpers.MODEL_CLASS_FULLNAME: 1}
|
||||
}
|
||||
return model_sym.node.metadata['django']['model_bases']
|
||||
return (model_sym.node.metadata
|
||||
.setdefault('django', {})
|
||||
.setdefault('model_bases', {helpers.MODEL_CLASS_FULLNAME: 1}))
|
||||
else:
|
||||
return {}
|
||||
|
||||
def _get_current_manager_bases(self) -> Dict[str, int]:
|
||||
manager_sym = self.lookup_fully_qualified(helpers.MANAGER_CLASS_FULLNAME)
|
||||
if manager_sym is not None and isinstance(manager_sym.node, TypeInfo):
|
||||
if 'django' not in manager_sym.node.metadata:
|
||||
manager_sym.node.metadata['django'] = {
|
||||
'manager_bases': {helpers.MANAGER_CLASS_FULLNAME: 1}
|
||||
}
|
||||
return manager_sym.node.metadata['django']['manager_bases']
|
||||
model_sym = self.lookup_fully_qualified(helpers.MANAGER_CLASS_FULLNAME)
|
||||
if model_sym is not None and isinstance(model_sym.node, TypeInfo):
|
||||
return (model_sym.node.metadata
|
||||
.setdefault('django', {})
|
||||
.setdefault('manager_bases', {helpers.MANAGER_CLASS_FULLNAME: 1}))
|
||||
else:
|
||||
return {}
|
||||
|
||||
def _get_current_modelform_bases(self) -> Dict[str, int]:
|
||||
model_sym = self.lookup_fully_qualified(helpers.MODELFORM_CLASS_FULLNAME)
|
||||
if model_sym is not None and isinstance(model_sym.node, TypeInfo):
|
||||
return (model_sym.node.metadata
|
||||
.setdefault('django', {})
|
||||
.setdefault('modelform_bases', {helpers.MODELFORM_CLASS_FULLNAME: 1}))
|
||||
else:
|
||||
return {}
|
||||
|
||||
@@ -176,43 +215,32 @@ class DjangoPlugin(Plugin):
|
||||
if fullname == 'django.contrib.auth.get_user_model':
|
||||
return return_user_model_hook
|
||||
|
||||
if fullname in {helpers.FOREIGN_KEY_FULLNAME,
|
||||
helpers.ONETOONE_FIELD_FULLNAME,
|
||||
helpers.MANYTOMANY_FIELD_FULLNAME}:
|
||||
return extract_to_parameter_as_get_ret_type_for_related_field
|
||||
|
||||
if fullname == 'django.contrib.postgres.fields.array.ArrayField':
|
||||
return determine_type_of_array_field
|
||||
|
||||
manager_bases = self._get_current_manager_bases()
|
||||
if fullname in manager_bases:
|
||||
return determine_proper_manager_type
|
||||
|
||||
sym = self.lookup_fully_qualified(fullname)
|
||||
if sym and isinstance(sym.node, TypeInfo):
|
||||
if sym is not None and isinstance(sym.node, TypeInfo):
|
||||
if sym.node.has_base(helpers.FIELD_FULLNAME):
|
||||
return record_field_properties_into_outer_model_class
|
||||
return fields.adjust_return_type_of_field_instantiation
|
||||
|
||||
if sym.node.metadata.get('django', {}).get('generated_init'):
|
||||
return init_create.redefine_and_typecheck_model_init
|
||||
|
||||
def get_method_hook(self, fullname: str
|
||||
) -> Optional[Callable[[MethodContext], Type]]:
|
||||
if fullname in {'django.apps.registry.Apps.get_model',
|
||||
'django.db.migrations.state.StateApps.get_model'}:
|
||||
return determine_model_cls_from_string_for_migrations
|
||||
|
||||
manager_classes = self._get_current_manager_bases()
|
||||
class_fullname, _, method_name = fullname.rpartition('.')
|
||||
if class_fullname in manager_classes and method_name == 'create':
|
||||
return init_create.redefine_and_typecheck_model_create
|
||||
|
||||
if fullname in {'django.apps.registry.Apps.get_model',
|
||||
'django.db.migrations.state.StateApps.get_model'}:
|
||||
return determine_model_cls_from_string_for_migrations
|
||||
return None
|
||||
|
||||
def get_base_class_hook(self, fullname: str
|
||||
) -> Optional[Callable[[ClassDefContext], None]]:
|
||||
if fullname in self._get_current_model_bases():
|
||||
return transform_model_class
|
||||
|
||||
if fullname == helpers.DUMMY_SETTINGS_BASE_CLASS:
|
||||
settings_modules = ['django.conf.global_settings']
|
||||
if self.django_settings_module:
|
||||
@@ -220,13 +248,22 @@ class DjangoPlugin(Plugin):
|
||||
return AddSettingValuesToDjangoConfObject(settings_modules,
|
||||
self.config.ignore_missing_settings)
|
||||
|
||||
if fullname in self._get_current_model_bases():
|
||||
return transform_model_class
|
||||
|
||||
if fullname in self._get_current_manager_bases():
|
||||
return transform_manager_class
|
||||
|
||||
if fullname in self._get_current_modelform_bases():
|
||||
return transform_modelform_class
|
||||
|
||||
return None
|
||||
|
||||
def get_attribute_hook(self, fullname: str
|
||||
) -> Optional[Callable[[AttributeContext], Type]]:
|
||||
if fullname == 'builtins.object.id':
|
||||
return return_integer_type_for_id_for_non_defined_primary_key_in_models
|
||||
|
||||
module, _, name = fullname.rpartition('.')
|
||||
sym = self.lookup_fully_qualified('django.conf.LazySettings')
|
||||
if sym and isinstance(sym.node, TypeInfo):
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
from typing import cast
|
||||
|
||||
from mypy.checker import TypeChecker
|
||||
from mypy.nodes import ListExpr, NameExpr, TupleExpr
|
||||
from mypy.plugin import FunctionContext
|
||||
from mypy.types import Instance, TupleType, Type
|
||||
|
||||
from mypy_django_plugin import helpers
|
||||
from mypy_django_plugin.plugins.models import iter_over_assignments
|
||||
|
||||
|
||||
def determine_type_of_array_field(ctx: FunctionContext) -> Type:
|
||||
base_field_arg_type = helpers.get_argument_type_by_name(ctx, 'base_field')
|
||||
if not base_field_arg_type or not isinstance(base_field_arg_type, Instance):
|
||||
return ctx.default_return_type
|
||||
|
||||
get_method = base_field_arg_type.type.get_method('__get__')
|
||||
if not get_method:
|
||||
# not a method
|
||||
return ctx.default_return_type
|
||||
|
||||
return ctx.api.named_generic_type(ctx.context.callee.fullname,
|
||||
args=[get_method.type.ret_type])
|
||||
|
||||
|
||||
def record_field_properties_into_outer_model_class(ctx: FunctionContext) -> Type:
|
||||
api = cast(TypeChecker, ctx.api)
|
||||
outer_model = api.scope.active_class()
|
||||
if outer_model is None or not outer_model.has_base(helpers.MODEL_CLASS_FULLNAME):
|
||||
# outside models.Model class, undetermined
|
||||
return ctx.default_return_type
|
||||
|
||||
field_name = None
|
||||
for name_expr, stmt in iter_over_assignments(outer_model.defn):
|
||||
if stmt == ctx.context and isinstance(name_expr, NameExpr):
|
||||
field_name = name_expr.name
|
||||
break
|
||||
if field_name is None:
|
||||
return ctx.default_return_type
|
||||
|
||||
fields_metadata = outer_model.metadata.setdefault('django', {}).setdefault('fields', {})
|
||||
|
||||
# primary key
|
||||
is_primary_key = False
|
||||
primary_key_arg = helpers.get_argument_by_name(ctx, 'primary_key')
|
||||
if primary_key_arg:
|
||||
is_primary_key = helpers.parse_bool(primary_key_arg)
|
||||
fields_metadata[field_name] = {'primary_key': is_primary_key}
|
||||
|
||||
# choices
|
||||
choices_arg = helpers.get_argument_by_name(ctx, 'choices')
|
||||
if choices_arg and isinstance(choices_arg, (TupleExpr, ListExpr)):
|
||||
# iterable of 2 element tuples of two kinds
|
||||
_, analyzed_choices = api.analyze_iterable_item_type(choices_arg)
|
||||
if isinstance(analyzed_choices, TupleType):
|
||||
first_element_type = analyzed_choices.items[0]
|
||||
if isinstance(first_element_type, Instance):
|
||||
fields_metadata[field_name]['choices'] = first_element_type.type.fullname()
|
||||
|
||||
# nullability
|
||||
null_arg = helpers.get_argument_by_name(ctx, 'null')
|
||||
is_nullable = False
|
||||
if null_arg:
|
||||
is_nullable = helpers.parse_bool(null_arg)
|
||||
fields_metadata[field_name]['null'] = is_nullable
|
||||
|
||||
# is_blankable
|
||||
blank_arg = helpers.get_argument_by_name(ctx, 'blank')
|
||||
is_blankable = False
|
||||
if blank_arg:
|
||||
is_blankable = helpers.parse_bool(blank_arg)
|
||||
fields_metadata[field_name]['blank'] = is_blankable
|
||||
|
||||
return ctx.default_return_type
|
||||
@@ -1,62 +0,0 @@
|
||||
from typing import Optional, cast
|
||||
|
||||
from mypy.checker import TypeChecker
|
||||
from mypy.nodes import StrExpr, TypeInfo
|
||||
from mypy.plugin import FunctionContext
|
||||
from mypy.types import CallableType, Instance, Type
|
||||
|
||||
from mypy_django_plugin import helpers
|
||||
from mypy_django_plugin.helpers import fill_typevars_with_any, reparametrize_with
|
||||
|
||||
|
||||
def get_valid_to_value_or_none(ctx: FunctionContext) -> Optional[Instance]:
|
||||
api = cast(TypeChecker, ctx.api)
|
||||
if 'to' not in ctx.callee_arg_names:
|
||||
# shouldn't happen, invalid code
|
||||
api.msg.fail(f'to= parameter must be set for {ctx.context.callee.fullname}',
|
||||
context=ctx.context)
|
||||
return None
|
||||
|
||||
arg_type = ctx.arg_types[ctx.callee_arg_names.index('to')][0]
|
||||
if not isinstance(arg_type, CallableType):
|
||||
to_arg_expr = ctx.args[ctx.callee_arg_names.index('to')][0]
|
||||
if not isinstance(to_arg_expr, StrExpr):
|
||||
# not string, not supported
|
||||
return None
|
||||
try:
|
||||
model_fullname = helpers.get_model_fullname_from_string(to_arg_expr.value,
|
||||
all_modules=api.modules)
|
||||
except helpers.SelfReference:
|
||||
model_fullname = api.tscope.classes[-1].fullname()
|
||||
|
||||
if model_fullname is None:
|
||||
return None
|
||||
model_info = helpers.lookup_fully_qualified_generic(model_fullname,
|
||||
all_modules=api.modules)
|
||||
if model_info is None or not isinstance(model_info, TypeInfo):
|
||||
return None
|
||||
return Instance(model_info, [])
|
||||
|
||||
referred_to_type = arg_type.ret_type
|
||||
if not isinstance(referred_to_type, Instance):
|
||||
return None
|
||||
if not referred_to_type.type.has_base(helpers.MODEL_CLASS_FULLNAME):
|
||||
ctx.api.msg.fail(f'to= parameter value must be '
|
||||
f'a subclass of {helpers.MODEL_CLASS_FULLNAME}',
|
||||
context=ctx.context)
|
||||
return None
|
||||
|
||||
return referred_to_type
|
||||
|
||||
|
||||
def extract_to_parameter_as_get_ret_type_for_related_field(ctx: FunctionContext) -> Type:
|
||||
try:
|
||||
referred_to_type = get_valid_to_value_or_none(ctx)
|
||||
except helpers.InvalidModelString as exc:
|
||||
ctx.api.fail(f'Invalid value for a to= parameter: {exc.model_string!r}', ctx.context)
|
||||
return fill_typevars_with_any(ctx.default_return_type)
|
||||
|
||||
if referred_to_type is None:
|
||||
# couldn't extract to= value
|
||||
return fill_typevars_with_any(ctx.default_return_type)
|
||||
return reparametrize_with(ctx.default_return_type, [referred_to_type])
|
||||
200
mypy_django_plugin/transformers/fields.py
Normal file
200
mypy_django_plugin/transformers/fields.py
Normal file
@@ -0,0 +1,200 @@
|
||||
from typing import Optional, cast
|
||||
|
||||
from mypy.checker import TypeChecker
|
||||
from mypy.nodes import ListExpr, NameExpr, StrExpr, TupleExpr, TypeInfo, Var
|
||||
from mypy.plugin import FunctionContext
|
||||
from mypy.types import AnyType, CallableType, Instance, TupleType, Type, TypeOfAny, UnionType
|
||||
from mypy_django_plugin import helpers
|
||||
from mypy_django_plugin.transformers.models import iter_over_assignments
|
||||
|
||||
|
||||
def extract_referred_to_type(ctx: FunctionContext) -> Optional[Instance]:
|
||||
api = cast(TypeChecker, ctx.api)
|
||||
if 'to' not in ctx.callee_arg_names:
|
||||
api.msg.fail(f'to= parameter must be set for {ctx.context.callee.fullname}',
|
||||
context=ctx.context)
|
||||
return None
|
||||
|
||||
arg_type = ctx.arg_types[ctx.callee_arg_names.index('to')][0]
|
||||
if not isinstance(arg_type, CallableType):
|
||||
to_arg_expr = ctx.args[ctx.callee_arg_names.index('to')][0]
|
||||
if not isinstance(to_arg_expr, StrExpr):
|
||||
# not string, not supported
|
||||
return None
|
||||
try:
|
||||
model_fullname = helpers.get_model_fullname_from_string(to_arg_expr.value,
|
||||
all_modules=api.modules)
|
||||
except helpers.SelfReference:
|
||||
model_fullname = api.tscope.classes[-1].fullname()
|
||||
|
||||
except helpers.SameFileModel as exc:
|
||||
model_fullname = api.tscope.classes[-1].module_name + '.' + exc.model_cls_name
|
||||
|
||||
if model_fullname is None:
|
||||
return None
|
||||
model_info = helpers.lookup_fully_qualified_generic(model_fullname,
|
||||
all_modules=api.modules)
|
||||
if model_info is None or not isinstance(model_info, TypeInfo):
|
||||
return None
|
||||
return Instance(model_info, [])
|
||||
|
||||
referred_to_type = arg_type.ret_type
|
||||
if not isinstance(referred_to_type, Instance):
|
||||
return None
|
||||
if not referred_to_type.type.has_base(helpers.MODEL_CLASS_FULLNAME):
|
||||
ctx.api.msg.fail(f'to= parameter value must be '
|
||||
f'a subclass of {helpers.MODEL_CLASS_FULLNAME}',
|
||||
context=ctx.context)
|
||||
return None
|
||||
|
||||
return referred_to_type
|
||||
|
||||
|
||||
def convert_any_to_type(typ: Type, referred_to_type: Type) -> Type:
|
||||
if isinstance(typ, UnionType):
|
||||
converted_items = []
|
||||
for item in typ.items:
|
||||
converted_items.append(convert_any_to_type(item, referred_to_type))
|
||||
return UnionType.make_union(converted_items,
|
||||
line=typ.line, column=typ.column)
|
||||
if isinstance(typ, Instance):
|
||||
args = []
|
||||
for default_arg in typ.args:
|
||||
if isinstance(default_arg, AnyType):
|
||||
args.append(referred_to_type)
|
||||
else:
|
||||
args.append(default_arg)
|
||||
return helpers.reparametrize_instance(typ, args)
|
||||
|
||||
if isinstance(typ, AnyType):
|
||||
return referred_to_type
|
||||
|
||||
return typ
|
||||
|
||||
|
||||
def fill_descriptor_types_for_related_field(ctx: FunctionContext) -> Type:
|
||||
default_return_type = set_descriptor_types_for_field(ctx)
|
||||
referred_to_type = extract_referred_to_type(ctx)
|
||||
if referred_to_type is None:
|
||||
return default_return_type
|
||||
|
||||
# replace Any with referred_to_type
|
||||
args = []
|
||||
for default_arg in default_return_type.args:
|
||||
args.append(convert_any_to_type(default_arg, referred_to_type))
|
||||
|
||||
return helpers.reparametrize_instance(ctx.default_return_type, new_args=args)
|
||||
|
||||
|
||||
def get_private_descriptor_type(type_info: TypeInfo, private_field_name: str, is_nullable: bool) -> Type:
|
||||
node = type_info.get(private_field_name).node
|
||||
if isinstance(node, Var):
|
||||
descriptor_type = node.type
|
||||
if is_nullable:
|
||||
descriptor_type = helpers.make_optional(descriptor_type)
|
||||
return descriptor_type
|
||||
return AnyType(TypeOfAny.unannotated)
|
||||
|
||||
|
||||
def set_descriptor_types_for_field(ctx: FunctionContext) -> Instance:
|
||||
default_return_type = cast(Instance, ctx.default_return_type)
|
||||
is_nullable = helpers.parse_bool(helpers.get_argument_by_name(ctx, 'null'))
|
||||
if not is_nullable and default_return_type.type.has_base(helpers.CHAR_FIELD_FULLNAME):
|
||||
# blank=True for CharField can be interpreted as null=True
|
||||
is_nullable = helpers.parse_bool(helpers.get_argument_by_name(ctx, 'blank'))
|
||||
|
||||
set_type = get_private_descriptor_type(default_return_type.type, '_pyi_private_set_type',
|
||||
is_nullable=is_nullable)
|
||||
get_type = get_private_descriptor_type(default_return_type.type, '_pyi_private_get_type',
|
||||
is_nullable=is_nullable)
|
||||
return helpers.reparametrize_instance(default_return_type, [set_type, get_type])
|
||||
|
||||
|
||||
def determine_type_of_array_field(ctx: FunctionContext) -> Type:
|
||||
default_return_type = set_descriptor_types_for_field(ctx)
|
||||
|
||||
base_field_arg_type = helpers.get_argument_type_by_name(ctx, 'base_field')
|
||||
if not base_field_arg_type or not isinstance(base_field_arg_type, Instance):
|
||||
return default_return_type
|
||||
|
||||
base_type = base_field_arg_type.args[1] # extract __get__ type
|
||||
args = []
|
||||
for default_arg in default_return_type.args:
|
||||
args.append(convert_any_to_type(default_arg, base_type))
|
||||
|
||||
return helpers.reparametrize_instance(default_return_type, args)
|
||||
|
||||
|
||||
def transform_into_proper_return_type(ctx: FunctionContext) -> Type:
|
||||
default_return_type = ctx.default_return_type
|
||||
if not isinstance(default_return_type, Instance):
|
||||
return default_return_type
|
||||
|
||||
if helpers.has_any_of_bases(default_return_type.type, (helpers.FOREIGN_KEY_FULLNAME,
|
||||
helpers.ONETOONE_FIELD_FULLNAME,
|
||||
helpers.MANYTOMANY_FIELD_FULLNAME)):
|
||||
return fill_descriptor_types_for_related_field(ctx)
|
||||
|
||||
if default_return_type.type.has_base(helpers.ARRAY_FIELD_FULLNAME):
|
||||
return determine_type_of_array_field(ctx)
|
||||
|
||||
return set_descriptor_types_for_field(ctx)
|
||||
|
||||
|
||||
def adjust_return_type_of_field_instantiation(ctx: FunctionContext) -> Type:
|
||||
record_field_properties_into_outer_model_class(ctx)
|
||||
return transform_into_proper_return_type(ctx)
|
||||
|
||||
|
||||
def record_field_properties_into_outer_model_class(ctx: FunctionContext) -> None:
|
||||
api = cast(TypeChecker, ctx.api)
|
||||
outer_model = api.scope.active_class()
|
||||
if outer_model is None or not outer_model.has_base(helpers.MODEL_CLASS_FULLNAME):
|
||||
# outside models.Model class, undetermined
|
||||
return
|
||||
|
||||
field_name = None
|
||||
for name_expr, stmt in iter_over_assignments(outer_model.defn):
|
||||
if stmt == ctx.context and isinstance(name_expr, NameExpr):
|
||||
field_name = name_expr.name
|
||||
break
|
||||
if field_name is None:
|
||||
return
|
||||
|
||||
fields_metadata = outer_model.metadata.setdefault('django', {}).setdefault('fields', {})
|
||||
|
||||
# primary key
|
||||
is_primary_key = False
|
||||
primary_key_arg = helpers.get_argument_by_name(ctx, 'primary_key')
|
||||
if primary_key_arg:
|
||||
is_primary_key = helpers.parse_bool(primary_key_arg)
|
||||
fields_metadata[field_name] = {'primary_key': is_primary_key}
|
||||
|
||||
# choices
|
||||
choices_arg = helpers.get_argument_by_name(ctx, 'choices')
|
||||
if choices_arg and isinstance(choices_arg, (TupleExpr, ListExpr)):
|
||||
# iterable of 2 element tuples of two kinds
|
||||
_, analyzed_choices = api.analyze_iterable_item_type(choices_arg)
|
||||
if isinstance(analyzed_choices, TupleType):
|
||||
first_element_type = analyzed_choices.items[0]
|
||||
if isinstance(first_element_type, Instance):
|
||||
fields_metadata[field_name]['choices'] = first_element_type.type.fullname()
|
||||
|
||||
# nullability
|
||||
null_arg = helpers.get_argument_by_name(ctx, 'null')
|
||||
is_nullable = False
|
||||
if null_arg:
|
||||
is_nullable = helpers.parse_bool(null_arg)
|
||||
fields_metadata[field_name]['null'] = is_nullable
|
||||
|
||||
# is_blankable
|
||||
blank_arg = helpers.get_argument_by_name(ctx, 'blank')
|
||||
is_blankable = False
|
||||
if blank_arg:
|
||||
is_blankable = helpers.parse_bool(blank_arg)
|
||||
fields_metadata[field_name]['blank'] = is_blankable
|
||||
|
||||
# default
|
||||
default_arg = helpers.get_argument_by_name(ctx, 'default')
|
||||
if default_arg and not helpers.is_none_expr(default_arg):
|
||||
fields_metadata[field_name]['default_specified'] = True
|
||||
9
mypy_django_plugin/transformers/forms.py
Normal file
9
mypy_django_plugin/transformers/forms.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from mypy.plugin import ClassDefContext
|
||||
from mypy_django_plugin import helpers
|
||||
|
||||
|
||||
def make_meta_nested_class_inherit_from_any(ctx: ClassDefContext) -> None:
|
||||
meta_node = helpers.get_nested_meta_node_for_current_class(ctx.cls.info)
|
||||
if meta_node is None:
|
||||
return None
|
||||
meta_node.fallback_to_any = True
|
||||
@@ -3,10 +3,10 @@ from typing import Dict, Optional, Set, cast
|
||||
from mypy.checker import TypeChecker
|
||||
from mypy.nodes import TypeInfo, Var
|
||||
from mypy.plugin import FunctionContext, MethodContext
|
||||
from mypy.types import AnyType, Instance, Type, TypeOfAny, UnionType
|
||||
|
||||
from mypy.types import AnyType, Instance, Type, TypeOfAny
|
||||
from mypy_django_plugin import helpers
|
||||
from mypy_django_plugin.helpers import extract_field_setter_type, extract_primary_key_type_for_set, get_fields_metadata
|
||||
from mypy_django_plugin.helpers import extract_field_setter_type, extract_explicit_set_type_of_model_primary_key, get_fields_metadata
|
||||
from mypy_django_plugin.transformers.fields import get_private_descriptor_type
|
||||
|
||||
|
||||
def extract_base_pointer_args(model: TypeInfo) -> Set[str]:
|
||||
@@ -25,12 +25,13 @@ def redefine_and_typecheck_model_init(ctx: FunctionContext) -> Type:
|
||||
api = cast(TypeChecker, ctx.api)
|
||||
model: TypeInfo = ctx.default_return_type.type
|
||||
|
||||
expected_types = extract_expected_types(ctx, model)
|
||||
# order is preserved, can use for positionals
|
||||
expected_types = extract_expected_types(ctx, model, is_init=True)
|
||||
|
||||
# order is preserved, can be used for positionals
|
||||
positional_names = list(expected_types.keys())
|
||||
positional_names.remove('pk')
|
||||
visited_positionals = set()
|
||||
|
||||
visited_positionals = set()
|
||||
# check positionals
|
||||
for i, (_, actual_pos_type) in enumerate(zip(ctx.arg_names[0], ctx.arg_types[0])):
|
||||
actual_pos_name = positional_names[i]
|
||||
@@ -111,42 +112,75 @@ def extract_choices_type(model: TypeInfo, field_name: str) -> Optional[str]:
|
||||
return None
|
||||
|
||||
|
||||
def extract_expected_types(ctx: FunctionContext, model: TypeInfo) -> Dict[str, Type]:
|
||||
expected_types: Dict[str, Type] = {}
|
||||
def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
|
||||
is_init: bool = False) -> Dict[str, Type]:
|
||||
api = cast(TypeChecker, ctx.api)
|
||||
|
||||
primary_key_type = extract_primary_key_type_for_set(model)
|
||||
expected_types: Dict[str, Type] = {}
|
||||
primary_key_type = extract_explicit_set_type_of_model_primary_key(model)
|
||||
if not primary_key_type:
|
||||
# no explicit primary key, set pk to Any and add id
|
||||
primary_key_type = AnyType(TypeOfAny.special_form)
|
||||
expected_types['id'] = ctx.api.named_generic_type('builtins.int', [])
|
||||
if is_init:
|
||||
expected_types['id'] = helpers.make_optional(ctx.api.named_generic_type('builtins.int', []))
|
||||
else:
|
||||
expected_types['id'] = ctx.api.named_generic_type('builtins.int', [])
|
||||
|
||||
expected_types['pk'] = primary_key_type
|
||||
|
||||
for base in model.mro:
|
||||
# extract all fields for all models in MRO
|
||||
for name, sym in base.names.items():
|
||||
# do not redefine special attrs
|
||||
if name in {'_meta', 'pk'}:
|
||||
continue
|
||||
|
||||
if isinstance(sym.node, Var):
|
||||
if sym.node.type is None or isinstance(sym.node.type, AnyType):
|
||||
typ = sym.node.type
|
||||
if typ is None or isinstance(typ, AnyType):
|
||||
# types are not ready, fallback to Any
|
||||
expected_types[name] = AnyType(TypeOfAny.from_unimported_type)
|
||||
expected_types[name + '_id'] = AnyType(TypeOfAny.from_unimported_type)
|
||||
|
||||
elif isinstance(sym.node.type, Instance):
|
||||
tp = sym.node.type
|
||||
field_type = extract_field_setter_type(tp)
|
||||
elif isinstance(typ, Instance):
|
||||
field_type = extract_field_setter_type(typ)
|
||||
if field_type is None:
|
||||
continue
|
||||
|
||||
if tp.type.fullname() in {helpers.FOREIGN_KEY_FULLNAME, helpers.ONETOONE_FIELD_FULLNAME}:
|
||||
ref_to_model = tp.args[0]
|
||||
primary_key_type = AnyType(TypeOfAny.special_form)
|
||||
if isinstance(ref_to_model, Instance) and ref_to_model.type.has_base(helpers.MODEL_CLASS_FULLNAME):
|
||||
typ = extract_primary_key_type_for_set(ref_to_model.type)
|
||||
if typ:
|
||||
primary_key_type = typ
|
||||
expected_types[name + '_id'] = primary_key_type
|
||||
if helpers.has_any_of_bases(typ.type, (helpers.FOREIGN_KEY_FULLNAME,
|
||||
helpers.ONETOONE_FIELD_FULLNAME)):
|
||||
related_primary_key_type = AnyType(TypeOfAny.implementation_artifact)
|
||||
# in case it's optional, we need Instance type
|
||||
referred_to_model = typ.args[1]
|
||||
is_nullable = helpers.is_optional(referred_to_model)
|
||||
if is_nullable:
|
||||
referred_to_model = helpers.make_required(typ.args[1])
|
||||
|
||||
if isinstance(referred_to_model, Instance) and referred_to_model.type.has_base(helpers.MODEL_CLASS_FULLNAME):
|
||||
pk_type = extract_explicit_set_type_of_model_primary_key(referred_to_model.type)
|
||||
if not pk_type:
|
||||
# extract set type of AutoField
|
||||
autofield_info = api.lookup_typeinfo('django.db.models.fields.AutoField')
|
||||
pk_type = get_private_descriptor_type(autofield_info, '_pyi_private_set_type',
|
||||
is_nullable=is_nullable)
|
||||
related_primary_key_type = pk_type
|
||||
|
||||
if is_init:
|
||||
related_primary_key_type = helpers.make_optional(related_primary_key_type)
|
||||
|
||||
expected_types[name + '_id'] = related_primary_key_type
|
||||
|
||||
field_metadata = get_fields_metadata(model).get(name, {})
|
||||
if field_type:
|
||||
# related fields could be None in __init__ (but should be specified before save())
|
||||
if helpers.has_any_of_bases(typ.type, (helpers.FOREIGN_KEY_FULLNAME,
|
||||
helpers.ONETOONE_FIELD_FULLNAME)) and is_init:
|
||||
field_type = helpers.make_optional(field_type)
|
||||
|
||||
# if primary_key=True and default specified
|
||||
elif field_metadata.get('primary_key', False) and field_metadata.get('default_specified', False):
|
||||
field_type = helpers.make_optional(field_type)
|
||||
|
||||
expected_types[name] = field_type
|
||||
|
||||
return expected_types
|
||||
@@ -4,7 +4,6 @@ from mypy.checker import TypeChecker
|
||||
from mypy.nodes import Expression, StrExpr, TypeInfo
|
||||
from mypy.plugin import MethodContext
|
||||
from mypy.types import Instance, Type, TypeType
|
||||
|
||||
from mypy_django_plugin import helpers
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@ from abc import ABCMeta, abstractmethod
|
||||
from typing import Dict, Iterator, List, Optional, Tuple, cast
|
||||
|
||||
import dataclasses
|
||||
from mypy.nodes import ARG_STAR, ARG_STAR2, Argument, CallExpr, ClassDef, Context, Expression, IndexExpr, \
|
||||
from mypy.nodes import ARG_STAR, ARG_STAR2, Argument, CallExpr, ClassDef, Expression, IndexExpr, \
|
||||
Lvalue, MDEF, MemberExpr, MypyFile, NameExpr, StrExpr, SymbolTableNode, TypeInfo, Var
|
||||
from mypy.plugin import ClassDefContext
|
||||
from mypy.plugins.common import add_method
|
||||
from mypy.semanal import SemanticAnalyzerPass2
|
||||
from mypy.types import AnyType, Instance, NoneTyp, TypeOfAny
|
||||
|
||||
from mypy_django_plugin import helpers
|
||||
from mypy_django_plugin.helpers import iter_over_assignments
|
||||
|
||||
@@ -22,14 +21,8 @@ class ModelClassInitializer(metaclass=ABCMeta):
|
||||
def from_ctx(cls, ctx: ClassDefContext):
|
||||
return cls(api=cast(SemanticAnalyzerPass2, ctx.api), model_classdef=ctx.cls)
|
||||
|
||||
def get_nested_meta_node(self) -> Optional[TypeInfo]:
|
||||
metaclass_sym = self.model_classdef.info.names.get('Meta')
|
||||
if metaclass_sym is not None and isinstance(metaclass_sym.node, TypeInfo):
|
||||
return metaclass_sym.node
|
||||
return None
|
||||
|
||||
def get_meta_attribute(self, name: str) -> Optional[Expression]:
|
||||
meta_node = self.get_nested_meta_node()
|
||||
meta_node = helpers.get_nested_meta_node_for_current_class(self.model_classdef.info)
|
||||
if meta_node is None:
|
||||
return None
|
||||
|
||||
@@ -74,8 +67,6 @@ def iter_over_one_to_n_related_fields(klass: ClassDef) -> Iterator[Tuple[NameExp
|
||||
class SetIdAttrsForRelatedFields(ModelClassInitializer):
|
||||
def run(self) -> None:
|
||||
for lvalue, rvalue in iter_over_one_to_n_related_fields(self.model_classdef):
|
||||
# base_model_info = self.api.named_type('builtins.object').type
|
||||
# helpers.get_related_field_primary_key_names(base_model_info).append(node_name)
|
||||
node_name = lvalue.name + '_id'
|
||||
self.add_new_node_to_model_class(name=node_name,
|
||||
typ=self.api.builtin_type('builtins.int'))
|
||||
@@ -83,7 +74,7 @@ class SetIdAttrsForRelatedFields(ModelClassInitializer):
|
||||
|
||||
class InjectAnyAsBaseForNestedMeta(ModelClassInitializer):
|
||||
def run(self) -> None:
|
||||
meta_node = self.get_nested_meta_node()
|
||||
meta_node = helpers.get_nested_meta_node_for_current_class(self.model_classdef.info)
|
||||
if meta_node is None:
|
||||
return None
|
||||
meta_node.fallback_to_any = True
|
||||
@@ -161,7 +152,7 @@ class AddIdAttributeIfPrimaryKeyTrueIsNotSet(ModelClassInitializer):
|
||||
and self.api.parse_bool(rvalue.args[rvalue.arg_names.index('primary_key')])):
|
||||
break
|
||||
else:
|
||||
self.add_new_node_to_model_class('id', self.api.builtin_type('builtins.int'))
|
||||
self.add_new_node_to_model_class('id', self.api.builtin_type('builtins.object'))
|
||||
|
||||
|
||||
class AddRelatedManagers(ModelClassInitializer):
|
||||
@@ -176,10 +167,9 @@ class AddRelatedManagers(ModelClassInitializer):
|
||||
all_modules=self.api.modules)
|
||||
except helpers.SelfReference:
|
||||
ref_to_fullname = defn.fullname
|
||||
except helpers.InvalidModelString as exc:
|
||||
self.api.fail(f'Invalid value for a to= parameter: {exc.model_string!r}',
|
||||
Context(line=rvalue.line))
|
||||
return None
|
||||
|
||||
except helpers.SameFileModel as exc:
|
||||
ref_to_fullname = module_name + '.' + exc.model_cls_name
|
||||
|
||||
if self.model_classdef.fullname == ref_to_fullname:
|
||||
related_manager_name = defn.name.lower() + '_set'
|
||||
@@ -4,6 +4,5 @@ testpaths = ./test-data
|
||||
addopts =
|
||||
--tb=native
|
||||
--mypy-ini-file=./test-data/plugins.ini
|
||||
--mypy-no-cache
|
||||
-s
|
||||
-v
|
||||
9
release.xsh
Normal file → Executable file
9
release.xsh
Normal file → Executable file
@@ -1,4 +1,9 @@
|
||||
#!/usr/local/bin/xonsh
|
||||
|
||||
python setup.py sdist
|
||||
twine upload dist/*
|
||||
try:
|
||||
pip install wheel
|
||||
python setup.py sdist bdist_wheel --universal
|
||||
twine upload dist/*
|
||||
|
||||
finally:
|
||||
rm -rf dist/ build/
|
||||
@@ -1,11 +1,12 @@
|
||||
[mypy]
|
||||
strict_optional = False
|
||||
strict_optional = True
|
||||
ignore_missing_imports = True
|
||||
check_untyped_defs = True
|
||||
warn_no_return = False
|
||||
show_traceback = True
|
||||
warn_redundant_casts = True
|
||||
allow_redefinition = True
|
||||
incremental = False
|
||||
|
||||
plugins =
|
||||
mypy_django_plugin.main
|
||||
|
||||
@@ -15,7 +15,7 @@ PROJECT_DIRECTORY = Path(__file__).parent.parent
|
||||
DJANGO_BRANCH = 'stable/2.1.x'
|
||||
|
||||
# Specific commit in the Django repository to check against
|
||||
DJANGO_COMMIT_SHA = '03219b5f709dcd5b0bfacd963508625557ec1ef0'
|
||||
DJANGO_COMMIT_SHA = '8fe63dc4cd637c1422a9bf3e3421d64388e14afd'
|
||||
|
||||
# Some errors occur for the test suite itself, and cannot be addressed via django-stubs. They should be ignored
|
||||
# using this constant.
|
||||
@@ -32,7 +32,7 @@ IGNORED_ERRORS = {
|
||||
'Cannot assign to a type',
|
||||
re.compile(r'Cannot assign to class variable "[a-z_]+" via instance'),
|
||||
# forms <-> models plugin support
|
||||
'"Model" has no attribute',
|
||||
# '"Model" has no attribute',
|
||||
re.compile(r'Cannot determine type of \'(objects|stuff)\''),
|
||||
# settings
|
||||
re.compile(r'Module has no attribute "[A-Z_]+"'),
|
||||
@@ -51,7 +51,11 @@ IGNORED_ERRORS = {
|
||||
# private members
|
||||
re.compile(r'has no attribute "|\'_[a-z][a-z_]+"|\''),
|
||||
'Invalid base class',
|
||||
'ValuesIterable'
|
||||
'ValuesIterable',
|
||||
'Value of type "Optional[Dict[str, Any]]" is not indexable',
|
||||
'Argument 1 to "len" has incompatible type "Optional[List[_Record]]"; expected "Sized"',
|
||||
'Argument 1 to "loads" has incompatible type "Union[bytes, str, None]"; expected "Union[str, bytes, bytearray]"',
|
||||
'Incompatible types in assignment (expression has type "None", variable has type Module)'
|
||||
],
|
||||
'admin_changelist': [
|
||||
'Incompatible types in assignment (expression has type "FilteredChildAdmin", variable has type "ChildAdmin")'
|
||||
@@ -62,7 +66,7 @@ IGNORED_ERRORS = {
|
||||
'admin_widgets': [
|
||||
'Incompatible types in assignment (expression has type "RelatedFieldWidgetWrapper", '
|
||||
'variable has type "AdminRadioSelect")',
|
||||
'Incompatible types in assignment (expression has type "Widget", variable has type "AutocompleteSelect")'
|
||||
'Incompatible types in assignment (expression has type "Union[Widget, Any]", variable has type "AutocompleteSelect")'
|
||||
],
|
||||
'admin_utils': [
|
||||
re.compile(r'Argument [0-9] to "lookup_field" has incompatible type'),
|
||||
@@ -78,13 +82,16 @@ IGNORED_ERRORS = {
|
||||
'"object" not callable',
|
||||
'Incompatible type for "pk" of "Collector" (got "int", expected "str")',
|
||||
re.compile('Unexpected attribute "[a-z]+" for model "Model"'),
|
||||
'Unexpected attribute "two_id" for model "CyclicOne"'
|
||||
'Unexpected attribute "two_id" for model "CyclicOne"',
|
||||
'Argument "is_dst" to "localize" of "BaseTzInfo" has incompatible type "None"; expected "bool"'
|
||||
],
|
||||
'aggregation': [
|
||||
'Incompatible types in assignment (expression has type "QuerySet[Any]", variable has type "List[Any]")',
|
||||
'"as_sql" undefined in superclass',
|
||||
'Incompatible types in assignment (expression has type "FlatValuesListIterable", '
|
||||
+ 'variable has type "ValuesListIterable")'
|
||||
+ 'variable has type "ValuesListIterable")',
|
||||
'Incompatible type for "contact" of "Book" (got "Optional[Author]", expected "Union[Author, Combinable]")',
|
||||
'Incompatible type for "publisher" of "Book" (got "Optional[Publisher]", expected "Union[Publisher, Combinable]")'
|
||||
],
|
||||
'aggregation_regress': [
|
||||
'Incompatible types in assignment (expression has type "List[str]", variable has type "QuerySet[Author]")',
|
||||
@@ -95,6 +102,9 @@ IGNORED_ERRORS = {
|
||||
'Incompatible types in assignment (expression has type "str", target has type "type")',
|
||||
'"Callable[[bool, bool], List[Type[Model]]]" has no attribute "cache_clear"'
|
||||
],
|
||||
'annotations': [
|
||||
'Incompatible type for "store" of "Employee" (got "Optional[Store]", expected "Union[Store, Combinable]")'
|
||||
],
|
||||
'auth_tests': [
|
||||
'"PasswordValidator" has no attribute "min_length"',
|
||||
'"validate_password" does not return a value',
|
||||
@@ -157,6 +167,29 @@ IGNORED_ERRORS = {
|
||||
'fixtures': [
|
||||
'Incompatible types in assignment (expression has type "int", target has type "Iterable[str]")'
|
||||
],
|
||||
'forms_tests': [
|
||||
'List item 0 has incompatible type "Jinja2"; expected "DjangoTemplates"',
|
||||
'Not enough arguments for format string',
|
||||
'Argument after ** must be a mapping, not "object"',
|
||||
'"media" undefined in superclass',
|
||||
'expression has type "None", base class "TestFormParent"',
|
||||
'variable has type "SongForm"',
|
||||
'"full_clean" of "BaseForm" does not return a value',
|
||||
'No overload variant of "zip" matches argument types "Tuple[str, str, str]", "object"',
|
||||
'note:',
|
||||
'Incompatible types in assignment (expression has type "GetDateShowHiddenInitial", variable has type "GetDate")',
|
||||
re.compile(r'Incompatible types in assignment \(expression has type "[a-zA-Z]+Field", '
|
||||
r'base class "BaseForm" defined the type as "Dict\[str, Any\]"\)'),
|
||||
'List or tuple expected as variable arguments',
|
||||
'Argument 1 to "__init__" of "MultiWidget" has incompatible type "List[object]"; '
|
||||
+ 'expected "Sequence[Union[Widget, Type[Widget]]]"',
|
||||
'Argument 1 to "issubclass" has incompatible type "ModelFormMetaclass"; expected "type"',
|
||||
'Incompatible types in assignment (expression has type "List[str]", target has type "str")',
|
||||
'Incompatible types in assignment (expression has type "TestForm", variable has type "Person")',
|
||||
'Incompatible types in assignment (expression has type "Type[Textarea]", '
|
||||
+ 'base class "Field" defined the type as "Widget")',
|
||||
'Incompatible types in assignment (expression has type "SimpleUploadedFile", variable has type "BinaryIO")'
|
||||
],
|
||||
'get_object_or_404': [
|
||||
'Argument 1 to "get_object_or_404" has incompatible type "str"; '
|
||||
+ 'expected "Union[Type[<nothing>], Manager[<nothing>], QuerySet[<nothing>]]"',
|
||||
@@ -165,11 +198,15 @@ IGNORED_ERRORS = {
|
||||
'CustomClass'
|
||||
],
|
||||
'get_or_create': [
|
||||
'Argument 1 to "update_or_create" of "QuerySet" has incompatible type "**Dict[str, object]"; expected "MutableMapping[str, Any]"'
|
||||
'Argument 1 to "update_or_create" of "QuerySet" has incompatible type "**Dict[str, object]"; '
|
||||
+ 'expected "Optional[MutableMapping[str, Any]]"'
|
||||
],
|
||||
'httpwrappers': [
|
||||
'Argument 2 to "appendlist" of "QueryDict" has incompatible type "List[str]"; expected "str"'
|
||||
],
|
||||
'humanize_tests': [
|
||||
'Argument 1 to "append" of "list" has incompatible type "None"; expected "str"'
|
||||
],
|
||||
'invalid_models_tests': [
|
||||
'Argument "max_length" to "CharField" has incompatible type "str"; expected "Optional[int]"',
|
||||
'Argument "choices" to "CharField" has incompatible type "str"'
|
||||
@@ -177,6 +214,9 @@ IGNORED_ERRORS = {
|
||||
'logging_tests': [
|
||||
re.compile('"(setUpClass|tearDownClass)" undefined in superclass')
|
||||
],
|
||||
'many_to_one': [
|
||||
'Incompatible type for "parent" of "Child" (got "None", expected "Union[Parent, Combinable]")'
|
||||
],
|
||||
'model_inheritance_regress': [
|
||||
'Incompatible types in assignment (expression has type "List[Supplier]", variable has type "QuerySet[Supplier]")'
|
||||
],
|
||||
@@ -189,7 +229,14 @@ IGNORED_ERRORS = {
|
||||
'Unexpected keyword argument "name" for "Person"',
|
||||
'Cannot assign multiple types to name "PersonTwoImages" without an explicit "Type[...]" annotation',
|
||||
'Incompatible types in assignment (expression has type "Type[Person]", '
|
||||
+ 'base class "ImageFieldTestMixin" defined the type as "Type[PersonWithHeightAndWidth]")'
|
||||
+ 'base class "ImageFieldTestMixin" defined the type as "Type[PersonWithHeightAndWidth]")',
|
||||
'note: "Person" defined here'
|
||||
],
|
||||
'model_formsets': [
|
||||
'Incompatible types in string interpolation (expression has type "object", placeholder has type "Union[int, float]")'
|
||||
],
|
||||
'model_formsets_regress': [
|
||||
'Incompatible types in assignment (expression has type "Model", variable has type "User")'
|
||||
],
|
||||
'model_regress': [
|
||||
'Too many arguments for "Worker"',
|
||||
@@ -203,6 +250,7 @@ IGNORED_ERRORS = {
|
||||
],
|
||||
'migrate_signals': [
|
||||
'Value of type "None" is not indexable',
|
||||
'Argument 1 to "set" has incompatible type "None"; expected "Iterable[<nothing>]"'
|
||||
],
|
||||
'migrations': [
|
||||
'FakeMigration',
|
||||
@@ -213,7 +261,8 @@ IGNORED_ERRORS = {
|
||||
+ 'expected "Optional[Sequence[Union[Type[Model], str]]]"',
|
||||
'Argument 1 to "RunPython" has incompatible type "str"; expected "Callable[..., Any]"',
|
||||
'FakeLoader',
|
||||
'Argument 1 to "append" of "list" has incompatible type "AddIndex"; expected "CreateModel"'
|
||||
'Argument 1 to "append" of "list" has incompatible type "AddIndex"; expected "CreateModel"',
|
||||
'Unsupported operand types for - ("Set[Any]" and "None")'
|
||||
],
|
||||
'middleware_exceptions': [
|
||||
'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any]"; expected "str"'
|
||||
@@ -227,15 +276,20 @@ IGNORED_ERRORS = {
|
||||
],
|
||||
'postgres_tests': [
|
||||
'Cannot assign multiple types to name',
|
||||
'Incompatible types in assignment (expression has type "Type[Field]',
|
||||
'Incompatible types in assignment (expression has type "Type[Field[Any, Any]]',
|
||||
'DummyArrayField',
|
||||
'DummyJSONField',
|
||||
'Argument "encoder" to "JSONField" has incompatible type "DjangoJSONEncoder"; expected "Optional[Type[JSONEncoder]]"',
|
||||
'for model "CITestModel"'
|
||||
'for model "CITestModel"',
|
||||
'Incompatible type for "field" of "IntegerArrayModel" (got "None", expected "Union[Sequence[int], Combinable]")'
|
||||
],
|
||||
'properties': [
|
||||
re.compile('Unexpected attribute "(full_name|full_name_2)" for model "Person"')
|
||||
],
|
||||
'queries': [
|
||||
'Incompatible types in assignment (expression has type "None", variable has type "str")',
|
||||
'Invalid index type "Optional[str]" for "Dict[str, int]"; expected type "str"'
|
||||
],
|
||||
'requests': [
|
||||
'Incompatible types in assignment (expression has type "Dict[str, str]", variable has type "QueryDict")'
|
||||
],
|
||||
@@ -248,7 +302,8 @@ IGNORED_ERRORS = {
|
||||
'has no attribute "read_by"'
|
||||
],
|
||||
'signals': [
|
||||
'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any, Any, Any]"; expected "Tuple[Any, Any, Any]"'
|
||||
'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any, Optional[Any], Any]"; '
|
||||
+ 'expected "Tuple[Any, Any, Any]"'
|
||||
],
|
||||
'syndication_tests': [
|
||||
'List or tuple expected as variable arguments'
|
||||
@@ -259,6 +314,14 @@ IGNORED_ERRORS = {
|
||||
'Argument 1 to "write" of "IO" has incompatible type "bytes"; expected "str"',
|
||||
'Value of type "object" is not indexable'
|
||||
],
|
||||
'schema': [
|
||||
'Incompatible type for "info" of "Note" (got "None", expected "Union[str, Combinable]")',
|
||||
'Incompatible type for "detail_info" of "NoteRename" (got "None", expected "Union[str, Combinable]")',
|
||||
'Incompatible type for "year" of "UniqueTest" (got "None", expected "Union[float, int, str, Combinable]")'
|
||||
],
|
||||
'settings_tests': [
|
||||
'Argument 1 to "Settings" has incompatible type "Optional[str]"; expected "str"'
|
||||
],
|
||||
'transactions': [
|
||||
'Incompatible types in assignment (expression has type "Thread", variable has type "Callable[[], Any]")'
|
||||
],
|
||||
@@ -267,7 +330,9 @@ IGNORED_ERRORS = {
|
||||
'Incompatible types in assignment (expression has type "HttpResponse", variable has type "StreamingHttpResponse")'
|
||||
],
|
||||
'test_client_regress': [
|
||||
'Incompatible types in assignment (expression has type "Dict[<nothing>, <nothing>]", variable has type "SessionBase")'
|
||||
'Incompatible types in assignment (expression has type "Dict[<nothing>, <nothing>]", variable has type "SessionBase")',
|
||||
'Unsupported left operand type for + ("None")',
|
||||
'Both left and right operands are unions'
|
||||
],
|
||||
'timezones': [
|
||||
'Too few arguments for "render" of "Template"'
|
||||
@@ -289,11 +354,12 @@ IGNORED_ERRORS = {
|
||||
'template_debug',
|
||||
'"yield from" can\'t be applied to',
|
||||
re.compile(r'List item [0-9] has incompatible type "URLResolver"; expected "URLPattern"'),
|
||||
'"WSGIRequest" has no attribute "current_app"'
|
||||
'"WSGIRequest" has no attribute "current_app"',
|
||||
'Value of type variable "AnyStr" of "urljoin" cannot be "Optional[str]"'
|
||||
],
|
||||
'template_backends': [
|
||||
'Incompatible import of "Jinja2" (imported name has type "Type[Jinja2]", local name has type "object")',
|
||||
'TemplateStringsTests'
|
||||
'TemplateStringsTests',
|
||||
],
|
||||
'urlpatterns': [
|
||||
'"object" has no attribute "__iter__"; maybe "__str__" or "__dir__"? (not iterable)',
|
||||
@@ -311,7 +377,8 @@ IGNORED_ERRORS = {
|
||||
"'django.urls.resolvers.ResolverMatch' object is not iterable"
|
||||
],
|
||||
'sessions_tests': [
|
||||
'base class "SessionTestsMixin" defined the type as "None")'
|
||||
'base class "SessionTestsMixin" defined the type as "None")',
|
||||
'Incompatible types in assignment (expression has type "None", variable has type "int")',
|
||||
],
|
||||
'select_related_onetoone': [
|
||||
'"None" has no attribute'
|
||||
@@ -402,7 +469,7 @@ TESTS_DIRS = [
|
||||
'flatpages_tests',
|
||||
'force_insert_update',
|
||||
'foreign_object',
|
||||
# TODO: 'forms_tests',
|
||||
'forms_tests',
|
||||
'from_db_value',
|
||||
'generic_inline_admin',
|
||||
'generic_relations',
|
||||
|
||||
10
setup.py
10
setup.py
@@ -31,12 +31,12 @@ if sys.version_info[:2] < (3, 7):
|
||||
|
||||
setup(
|
||||
name="django-stubs",
|
||||
version="0.5.0",
|
||||
version="0.7.0",
|
||||
description='Django mypy stubs',
|
||||
long_description=readme,
|
||||
long_description_content_type='text/markdown',
|
||||
license='BSD',
|
||||
url="https://github.com/mkurnikov/django-stubs.git",
|
||||
license='MIT',
|
||||
url="https://github.com/mkurnikov/django-stubs",
|
||||
author="Maksim Kurnikov",
|
||||
author_email="maxim.kurnikov@gmail.com",
|
||||
py_modules=[],
|
||||
@@ -46,6 +46,8 @@ setup(
|
||||
package_data={'django-stubs': find_stub_files('django-stubs')},
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Programming Language :: Python :: 3'
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7'
|
||||
]
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[mypy]
|
||||
incremental = False
|
||||
incremental = True
|
||||
strict_optional = True
|
||||
plugins =
|
||||
mypy_django_plugin.main
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
[CASE missing_settings_ignored_flag]
|
||||
[env MYPY_DJANGO_CONFIG=${MYPY_CWD}/mypy_django.ini]
|
||||
[disable_cache]
|
||||
from django.conf import settings
|
||||
reveal_type(settings.NO_SUCH_SETTING) # E: Revealed type is 'Any'
|
||||
|
||||
[env MYPY_DJANGO_CONFIG=${MYPY_CWD}/mypy_django.ini]
|
||||
|
||||
[file mypy_django.ini]
|
||||
[[mypy_django_plugin]
|
||||
ignore_missing_settings = True
|
||||
[out]
|
||||
[/CASE]
|
||||
|
||||
[CASE django_settings_via_config_file]
|
||||
[env MYPY_DJANGO_CONFIG=${MYPY_CWD}/mypy_django.ini]
|
||||
[disable_cache]
|
||||
from django.conf import settings
|
||||
reveal_type(settings.MY_SETTING) # E: Revealed type is 'builtins.int'
|
||||
|
||||
[env MYPY_DJANGO_CONFIG=${MYPY_CWD}/mypy_django.ini]
|
||||
[file mypy_django.ini]
|
||||
[[mypy_django_plugin]
|
||||
django_settings = mysettings
|
||||
|
||||
[file mysettings.py]
|
||||
MY_SETTING: int = 1
|
||||
[out]
|
||||
[/CASE]
|
||||
|
||||
[CASE mypy_django_ini_in_current_directory_is_a_default]
|
||||
[disable_cache]
|
||||
from django.conf import settings
|
||||
reveal_type(settings.MY_SETTING) # E: Revealed type is 'builtins.int'
|
||||
|
||||
@@ -32,4 +34,4 @@ django_settings = mysettings
|
||||
|
||||
[file mysettings.py]
|
||||
MY_SETTING: int = 1
|
||||
[out]
|
||||
[/CASE]
|
||||
|
||||
@@ -6,7 +6,8 @@ class User(models.Model):
|
||||
array = ArrayField(base_field=models.Field())
|
||||
|
||||
user = User()
|
||||
reveal_type(user.array) # E: Revealed type is 'builtins.list[Any]'
|
||||
reveal_type(user.array) # E: Revealed type is 'builtins.list*[Any]'
|
||||
[/CASE]
|
||||
|
||||
[CASE array_field_base_field_parsed_into_generic_typevar]
|
||||
from django.db import models
|
||||
@@ -17,8 +18,9 @@ class User(models.Model):
|
||||
members_as_text = ArrayField(base_field=models.CharField(max_length=255))
|
||||
|
||||
user = User()
|
||||
reveal_type(user.members) # E: Revealed type is 'builtins.list[builtins.int*]'
|
||||
reveal_type(user.members_as_text) # E: Revealed type is 'builtins.list[builtins.str*]'
|
||||
reveal_type(user.members) # E: Revealed type is 'builtins.list*[builtins.int]'
|
||||
reveal_type(user.members_as_text) # E: Revealed type is 'builtins.list*[builtins.str]'
|
||||
[/CASE]
|
||||
|
||||
[CASE test_model_fields_classes_present_as_primitives]
|
||||
from django.db import models
|
||||
@@ -31,13 +33,14 @@ class User(models.Model):
|
||||
text = models.TextField()
|
||||
|
||||
user = User()
|
||||
reveal_type(user.id) # E: Revealed type is 'builtins.int'
|
||||
reveal_type(user.small_int) # E: Revealed type is 'builtins.int'
|
||||
reveal_type(user.name) # E: Revealed type is 'builtins.str'
|
||||
reveal_type(user.slug) # E: Revealed type is 'builtins.str'
|
||||
reveal_type(user.text) # E: Revealed type is 'builtins.str'
|
||||
reveal_type(user.id) # E: Revealed type is 'builtins.int*'
|
||||
reveal_type(user.small_int) # E: Revealed type is 'builtins.int*'
|
||||
reveal_type(user.name) # E: Revealed type is 'builtins.str*'
|
||||
reveal_type(user.slug) # E: Revealed type is 'builtins.str*'
|
||||
reveal_type(user.text) # E: Revealed type is 'builtins.str*'
|
||||
[/CASE]
|
||||
|
||||
[CASE test_model_field_classes_from_exciting_locations]
|
||||
[CASE test_model_field_classes_from_existing_locations]
|
||||
from django.db import models
|
||||
from django.contrib.postgres import fields as pg_fields
|
||||
from decimal import Decimal
|
||||
@@ -48,9 +51,10 @@ class Booking(models.Model):
|
||||
some_decimal = models.DecimalField(max_digits=10, decimal_places=5)
|
||||
|
||||
booking = Booking()
|
||||
reveal_type(booking.id) # E: Revealed type is 'builtins.int'
|
||||
reveal_type(booking.id) # E: Revealed type is 'builtins.int*'
|
||||
reveal_type(booking.time_range) # E: Revealed type is 'Any'
|
||||
reveal_type(booking.some_decimal) # E: Revealed type is 'decimal.Decimal'
|
||||
reveal_type(booking.some_decimal) # E: Revealed type is 'decimal.Decimal*'
|
||||
[/CASE]
|
||||
|
||||
[CASE test_add_id_field_if_no_primary_key_defined]
|
||||
from django.db import models
|
||||
@@ -59,6 +63,7 @@ class User(models.Model):
|
||||
pass
|
||||
|
||||
reveal_type(User().id) # E: Revealed type is 'builtins.int'
|
||||
[/CASE]
|
||||
|
||||
[CASE test_do_not_add_id_if_field_with_primary_key_True_defined]
|
||||
from django.db import models
|
||||
@@ -66,9 +71,9 @@ from django.db import models
|
||||
class User(models.Model):
|
||||
my_pk = models.IntegerField(primary_key=True)
|
||||
|
||||
reveal_type(User().my_pk) # E: Revealed type is 'builtins.int'
|
||||
reveal_type(User().my_pk) # E: Revealed type is 'builtins.int*'
|
||||
reveal_type(User().id) # E: Revealed type is 'Any'
|
||||
[out]
|
||||
[/CASE]
|
||||
|
||||
[CASE test_meta_nested_class_allows_subclassing_in_multiple_inheritance]
|
||||
from typing import Any
|
||||
@@ -84,7 +89,7 @@ class Mixin2(models.Model):
|
||||
|
||||
class User(Mixin1, Mixin2):
|
||||
pass
|
||||
[out]
|
||||
[/CASE]
|
||||
|
||||
[CASE test_inheritance_from_abstract_model_does_not_fail_if_field_with_id_exists]
|
||||
from django.db import models
|
||||
@@ -93,4 +98,21 @@ class Abstract(models.Model):
|
||||
abstract = True
|
||||
class User(Abstract):
|
||||
id = models.AutoField(primary_key=True)
|
||||
[out]
|
||||
[/CASE]
|
||||
|
||||
[CASE standard_it_from_parent_model_could_be_overridden_with_non_integer_field_in_child_model]
|
||||
from django.db import models
|
||||
import uuid
|
||||
class ParentModel(models.Model):
|
||||
pass
|
||||
class MyModel(ParentModel):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
reveal_type(MyModel().id) # E: Revealed type is 'uuid.UUID*'
|
||||
[/CASE]
|
||||
|
||||
[CASE blank_for_charfield_is_the_same_as_null]
|
||||
from django.db import models
|
||||
class MyModel(models.Model):
|
||||
text = models.CharField(max_length=30, blank=True)
|
||||
MyModel(text=None)
|
||||
[/CASE]
|
||||
|
||||
19
test-data/typecheck/forms.test
Normal file
19
test-data/typecheck/forms.test
Normal file
@@ -0,0 +1,19 @@
|
||||
[CASE no_incompatible_meta_nested_class_false_positive]
|
||||
from django.db import models
|
||||
from django import forms
|
||||
|
||||
class Article(models.Model):
|
||||
pass
|
||||
class Category(models.Model):
|
||||
pass
|
||||
class ArticleForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Article
|
||||
fields = '__all__'
|
||||
class CategoryForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Category
|
||||
fields = '__all__'
|
||||
class CompositeForm(ArticleForm, CategoryForm):
|
||||
pass
|
||||
[out]
|
||||
@@ -6,7 +6,7 @@ class User(models.Model):
|
||||
age = models.IntegerField()
|
||||
|
||||
User.objects.create(name='Max', age=10)
|
||||
User.objects.create(age='hello') # E: Incompatible type for "age" of "User" (got "str", expected "Union[int, Combinable, Literal['']]")
|
||||
User.objects.create(age=[]) # E: Incompatible type for "age" of "User" (got "List[Any]", expected "Union[float, int, str, Combinable]")
|
||||
[out]
|
||||
|
||||
[CASE model_recognises_parent_attributes]
|
||||
@@ -31,4 +31,34 @@ class Child1(Parent1, Parent2):
|
||||
value = models.IntegerField()
|
||||
class Child4(Child1):
|
||||
value4 = models.IntegerField()
|
||||
Child4.objects.create(name1='n1', name2='n2', value=1, value4=4)
|
||||
Child4.objects.create(name1='n1', name2='n2', value=1, value4=4)
|
||||
[out]
|
||||
|
||||
[CASE optional_primary_key_for_create_is_error]
|
||||
from django.db import models
|
||||
class MyModel(models.Model):
|
||||
pass
|
||||
MyModel.objects.create(id=None) # E: Incompatible type for "id" of "MyModel" (got "None", expected "int")
|
||||
|
||||
[CASE optional_related_model_for_create_is_error]
|
||||
from django.db import models
|
||||
class Publisher(models.Model):
|
||||
pass
|
||||
class Book(models.Model):
|
||||
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
|
||||
Book.objects.create(publisher=None) # E: Incompatible type for "publisher" of "Book" (got "None", expected "Union[Publisher, Combinable]")
|
||||
|
||||
[CASE when_default_for_primary_key_is_specified_allow_none_to_be_set]
|
||||
from django.db import models
|
||||
def return_int():
|
||||
return 0
|
||||
class MyModel(models.Model):
|
||||
id = models.IntegerField(primary_key=True, default=return_int)
|
||||
MyModel(id=None)
|
||||
MyModel.objects.create(id=None)
|
||||
|
||||
class MyModel2(models.Model):
|
||||
id = models.IntegerField(primary_key=True, default=None)
|
||||
MyModel2(id=None) # E: Incompatible type for "id" of "MyModel2" (got "None", expected "Union[float, int, str, Combinable]")
|
||||
MyModel2.objects.create(id=None) # E: Incompatible type for "id" of "MyModel2" (got "None", expected "Union[float, int, str, Combinable]")
|
||||
[out]
|
||||
@@ -14,9 +14,9 @@ from django.db import models
|
||||
class MyUser(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
age = models.IntegerField()
|
||||
user = MyUser(name='hello', age='world')
|
||||
user = MyUser(name='hello', age=[])
|
||||
[out]
|
||||
main:6: error: Incompatible type for "age" of "MyUser" (got "str", expected "Union[int, Combinable, Literal['']]")
|
||||
main:6: error: Incompatible type for "age" of "MyUser" (got "List[Any]", expected "Union[float, int, str, Combinable]")
|
||||
|
||||
[CASE arguments_to_init_combined_from_base_classes]
|
||||
from django.db import models
|
||||
@@ -63,7 +63,7 @@ from django.db import models
|
||||
|
||||
class MyUser1(models.Model):
|
||||
mypk = models.IntegerField(primary_key=True)
|
||||
user = MyUser1(pk='hello') # E: Incompatible type for "pk" of "MyUser1" (got "str", expected "Union[int, Combinable, Literal['']]")
|
||||
user = MyUser1(pk=[]) # E: Incompatible type for "pk" of "MyUser1" (got "List[Any]", expected "Union[float, int, str, Combinable]")
|
||||
[out]
|
||||
|
||||
[CASE can_set_foreign_key_by_its_primary_key]
|
||||
@@ -71,14 +71,15 @@ from django.db import models
|
||||
|
||||
class Publisher(models.Model):
|
||||
pass
|
||||
class PublisherWithCharPK(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
class PublisherDatetime(models.Model):
|
||||
dt_pk = models.DateTimeField(primary_key=True)
|
||||
class Book(models.Model):
|
||||
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
|
||||
publisher_with_char_pk = models.ForeignKey(PublisherWithCharPK, on_delete=models.CASCADE)
|
||||
publisher_dt = models.ForeignKey(PublisherDatetime, on_delete=models.CASCADE)
|
||||
|
||||
Book(publisher_id=1, publisher_with_char_pk_id=1)
|
||||
Book(publisher_id=1, publisher_with_char_pk_id='hello') # E: Incompatible type for "publisher_with_char_pk_id" of "Book" (got "str", expected "Union[int, Combinable, Literal['']]")
|
||||
Book(publisher_id=1)
|
||||
Book(publisher_id=[]) # E: Incompatible type for "publisher_id" of "Book" (got "List[Any]", expected "Union[Combinable, int, str, None]")
|
||||
Book(publisher_dt_id=11) # E: Incompatible type for "publisher_dt_id" of "Book" (got "int", expected "Union[str, date, Combinable, None]")
|
||||
[out]
|
||||
|
||||
[CASE setting_value_to_an_array_of_ints]
|
||||
@@ -94,7 +95,7 @@ MyModel(array=array_val)
|
||||
array_val2: List[int] = [1]
|
||||
MyModel(array=array_val2)
|
||||
array_val3: List[str] = ['hello']
|
||||
MyModel(array=array_val3) # E: Incompatible type for "array" of "MyModel" (got "List[str]", expected "Sequence[int]")
|
||||
MyModel(array=array_val3) # E: Incompatible type for "array" of "MyModel" (got "List[str]", expected "Union[Sequence[int], Combinable]")
|
||||
[out]
|
||||
|
||||
[CASE if_no_explicit_primary_key_id_can_be_passed]
|
||||
@@ -114,7 +115,7 @@ MyModel(1)
|
||||
class MyModel2(models.Model):
|
||||
name = models.IntegerField()
|
||||
MyModel2(1, 12)
|
||||
MyModel2(1, 'Maxim') # E: Incompatible type for "name" of "MyModel2" (got "str", expected "Union[int, Combinable, Literal['']]")
|
||||
MyModel2(1, []) # E: Incompatible type for "name" of "MyModel2" (got "List[Any]", expected "Union[float, int, str, Combinable]")
|
||||
[out]
|
||||
|
||||
[CASE arguments_passed_as_dictionary_unpacking_are_not_supported]
|
||||
@@ -135,20 +136,6 @@ Restaurant(place_ptr=place)
|
||||
Restaurant(place_ptr_id=place.id)
|
||||
[out]
|
||||
|
||||
[CASE extract_type_of_init_param_from_set_method]
|
||||
from typing import Union
|
||||
from datetime import time
|
||||
|
||||
from django.db import models
|
||||
class MyField(models.Field):
|
||||
def __set__(self, instance, value: Union[str, time]) -> None: pass
|
||||
def __get__(self, instance, owner) -> time: pass
|
||||
class MyModel(models.Model):
|
||||
field = MyField()
|
||||
MyModel(field=time())
|
||||
MyModel(field='12:00')
|
||||
MyModel(field=100) # E: Incompatible type for "field" of "MyModel" (got "int", expected "Union[str, time]")
|
||||
|
||||
[CASE charfield_with_integer_choices]
|
||||
from django.db import models
|
||||
class MyModel(models.Model):
|
||||
@@ -171,3 +158,20 @@ InvoiceRow.objects.create(base_amount=Decimal(0), vat_rate=Decimal(0))
|
||||
main:3: error: Cannot find module named 'fields2'
|
||||
main:3: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
|
||||
|
||||
[CASE optional_primary_key_is_allowed_for_init]
|
||||
from django.db import models
|
||||
class MyModel(models.Model):
|
||||
pass
|
||||
MyModel(id=None)
|
||||
MyModel(None)
|
||||
[out]
|
||||
|
||||
[CASE optional_related_model_is_allowed_for_init]
|
||||
from django.db import models
|
||||
class Publisher(models.Model):
|
||||
pass
|
||||
class Book(models.Model):
|
||||
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
|
||||
Book(publisher=None)
|
||||
Book(publisher_id=None)
|
||||
[out]
|
||||
42
test-data/typecheck/nullable_fields.test
Normal file
42
test-data/typecheck/nullable_fields.test
Normal file
@@ -0,0 +1,42 @@
|
||||
[CASE nullable_field_with_strict_optional_true]
|
||||
from django.db import models
|
||||
class MyModel(models.Model):
|
||||
text_nullable = models.CharField(max_length=100, null=True)
|
||||
text = models.CharField(max_length=100)
|
||||
reveal_type(MyModel().text) # E: Revealed type is 'builtins.str*'
|
||||
reveal_type(MyModel().text_nullable) # E: Revealed type is 'Union[builtins.str, None]'
|
||||
MyModel().text = None # E: Incompatible types in assignment (expression has type "None", variable has type "Union[str, int, Combinable]")
|
||||
MyModel().text_nullable = None
|
||||
[out]
|
||||
|
||||
[CASE nullable_array_field]
|
||||
from django.db import models
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
|
||||
class MyModel(models.Model):
|
||||
lst = ArrayField(base_field=models.CharField(max_length=100), null=True)
|
||||
reveal_type(MyModel().lst) # E: Revealed type is 'Union[builtins.list[builtins.str], None]'
|
||||
[out]
|
||||
|
||||
[CASE nullable_foreign_key]
|
||||
from django.db import models
|
||||
|
||||
class Publisher(models.Model):
|
||||
pass
|
||||
class Book(models.Model):
|
||||
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE, null=True)
|
||||
reveal_type(Book().publisher) # E: Revealed type is 'Union[main.Publisher, None]'
|
||||
Book().publisher = 11 # E: Incompatible types in assignment (expression has type "int", variable has type "Union[Publisher, Combinable, None]")
|
||||
[out]
|
||||
|
||||
[CASE nullable_self_foreign_key]
|
||||
from django.db import models
|
||||
class Inventory(models.Model):
|
||||
parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True)
|
||||
parent = Inventory()
|
||||
core = Inventory(parent_id=parent.id)
|
||||
reveal_type(core.parent_id) # E: Revealed type is 'Union[builtins.int, None]'
|
||||
reveal_type(core.parent) # E: Revealed type is 'Union[main.Inventory, None]'
|
||||
Inventory(parent=None)
|
||||
Inventory(parent_id=None)
|
||||
[out]
|
||||
@@ -191,6 +191,8 @@ class Profile(models.Model):
|
||||
from django.db import models
|
||||
class App(models.Model):
|
||||
owner = models.ForeignKey(to='myapp.User', on_delete=models.CASCADE, related_name='apps')
|
||||
[disable_cache]
|
||||
[/CASE]
|
||||
|
||||
[CASE many_to_many_field_converts_to_queryset_of_model_type]
|
||||
from django.db import models
|
||||
@@ -198,7 +200,7 @@ class App(models.Model):
|
||||
pass
|
||||
class Member(models.Model):
|
||||
apps = models.ManyToManyField(to=App, related_name='members')
|
||||
reveal_type(Member().apps) # E: Revealed type is 'django.db.models.manager.RelatedManager[main.App*]'
|
||||
reveal_type(Member().apps) # E: Revealed type is 'django.db.models.manager.RelatedManager*[main.App]'
|
||||
reveal_type(App().members) # E: Revealed type is 'django.db.models.manager.RelatedManager[main.Member]'
|
||||
[out]
|
||||
|
||||
@@ -207,7 +209,7 @@ from django.db import models
|
||||
from myapp.models import App
|
||||
class Member(models.Model):
|
||||
apps = models.ManyToManyField(to='myapp.App', related_name='members')
|
||||
reveal_type(Member().apps) # E: Revealed type is 'django.db.models.manager.RelatedManager[myapp.models.App*]'
|
||||
reveal_type(Member().apps) # E: Revealed type is 'django.db.models.manager.RelatedManager*[myapp.models.App]'
|
||||
|
||||
[file myapp/__init__.py]
|
||||
[file myapp/models.py]
|
||||
@@ -226,8 +228,8 @@ reveal_type(User().parent) # E: Revealed type is 'main.User*'
|
||||
[CASE many_to_many_with_self]
|
||||
from django.db import models
|
||||
class User(models.Model):
|
||||
friends = models.ManyToManyField('self', on_delete=models.CASCADE)
|
||||
reveal_type(User().friends) # E: Revealed type is 'django.db.models.manager.RelatedManager[main.User*]'
|
||||
friends = models.ManyToManyField('self')
|
||||
reveal_type(User().friends) # E: Revealed type is 'django.db.models.manager.RelatedManager*[main.User]'
|
||||
[out]
|
||||
|
||||
[CASE recursively_checking_for_base_model_in_to_parameter]
|
||||
@@ -260,7 +262,7 @@ class Book(models.Model):
|
||||
reveal_type(Book().publisher_id) # E: Revealed type is 'builtins.str'
|
||||
Book(publisher_id=1)
|
||||
Book(publisher_id='hello')
|
||||
Book(publisher_id=datetime.datetime.now()) # E: Incompatible type for "publisher_id" of "Book" (got "datetime", expected "Union[str, int, Combinable]")
|
||||
Book(publisher_id=datetime.datetime.now()) # E: Incompatible type for "publisher_id" of "Book" (got "datetime", expected "Union[str, int, Combinable, None]")
|
||||
Book.objects.create(publisher_id=1)
|
||||
Book.objects.create(publisher_id='hello')
|
||||
|
||||
@@ -271,7 +273,17 @@ class Book2(models.Model):
|
||||
|
||||
reveal_type(Book2().publisher_id) # E: Revealed type is 'builtins.int'
|
||||
Book2(publisher_id=1)
|
||||
Book2(publisher_id='hello') # E: Incompatible type for "publisher_id" of "Book2" (got "str", expected "Union[int, Combinable, Literal['']]")
|
||||
Book2(publisher_id=[]) # E: Incompatible type for "publisher_id" of "Book2" (got "List[Any]", expected "Union[float, int, str, Combinable, None]")
|
||||
Book2.objects.create(publisher_id=1)
|
||||
Book2.objects.create(publisher_id='hello') # E: Incompatible type for "publisher_id" of "Book2" (got "str", expected "Union[int, Combinable, Literal['']]")
|
||||
Book2.objects.create(publisher_id=[]) # E: Incompatible type for "publisher_id" of "Book2" (got "List[Any]", expected "Union[float, int, str, Combinable]")
|
||||
[out]
|
||||
|
||||
[CASE if_model_is_defined_as_name_of_the_class_look_for_it_in_the_same_file]
|
||||
from django.db import models
|
||||
|
||||
class Book(models.Model):
|
||||
publisher = models.ForeignKey(to='Publisher', on_delete=models.CASCADE)
|
||||
class Publisher(models.Model):
|
||||
pass
|
||||
reveal_type(Book().publisher) # E: Revealed type is 'main.Publisher*'
|
||||
[out]
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
[CASE test_settings_are_parsed_into_django_conf_settings]
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[disable_cache]
|
||||
from django.conf import settings
|
||||
|
||||
reveal_type(settings.ROOT_DIR) # E: Revealed type is 'builtins.str'
|
||||
@@ -6,7 +8,6 @@ reveal_type(settings.APPS_DIR) # E: Revealed type is 'pathlib.Path'
|
||||
reveal_type(settings.OBJ) # E: Revealed type is 'django.utils.functional.LazyObject'
|
||||
reveal_type(settings.NUMBERS) # E: Revealed type is 'builtins.list[builtins.str]'
|
||||
reveal_type(settings.DICT) # E: Revealed type is 'builtins.dict[Any, Any]'
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[file base.py]
|
||||
from pathlib import Path
|
||||
ROOT_DIR = '/etc'
|
||||
@@ -18,14 +19,16 @@ NUMBERS = ['one', 'two']
|
||||
DICT = {} # type: ignore
|
||||
from django.utils.functional import LazyObject
|
||||
OBJ = LazyObject()
|
||||
[/CASE]
|
||||
|
||||
[CASE test_settings_could_be_defined_in_different_module_and_imported_with_star]
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[disable_cache]
|
||||
from django.conf import settings
|
||||
|
||||
reveal_type(settings.ROOT_DIR) # E: Revealed type is 'pathlib.Path'
|
||||
reveal_type(settings.SETUP) # E: Revealed type is 'builtins.int'
|
||||
reveal_type(settings.DATABASES) # E: Revealed type is 'builtins.dict[builtins.str, builtins.str]'
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[file mysettings.py]
|
||||
from local import *
|
||||
DATABASES = {'default': 'mydb'}
|
||||
@@ -36,24 +39,25 @@ SETUP = 3
|
||||
from pathlib import Path
|
||||
|
||||
ROOT_DIR = Path(__file__)
|
||||
[/CASE]
|
||||
|
||||
[CASE global_settings_are_always_loaded]
|
||||
from django.conf import settings
|
||||
|
||||
reveal_type(settings.AUTH_USER_MODEL) # E: Revealed type is 'builtins.str'
|
||||
reveal_type(settings.AUTHENTICATION_BACKENDS) # E: Revealed type is 'builtins.list[builtins.str]'
|
||||
[out]
|
||||
reveal_type(settings.AUTHENTICATION_BACKENDS) # E: Revealed type is 'typing.Sequence[builtins.str]'
|
||||
[/CASE]
|
||||
|
||||
[CASE test_circular_dependency_in_settings_works_if_settings_have_annotations]
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[disable_cache]
|
||||
from django.conf import settings
|
||||
class Class:
|
||||
pass
|
||||
reveal_type(settings.MYSETTING) # E: Revealed type is 'builtins.int'
|
||||
reveal_type(settings.REGISTRY) # E: Revealed type is 'Union[main.Class, None]'
|
||||
reveal_type(settings.LIST) # E: Revealed type is 'builtins.list[builtins.str]'
|
||||
[out]
|
||||
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[file mysettings.py]
|
||||
from typing import TYPE_CHECKING, Optional, List
|
||||
|
||||
@@ -63,13 +67,16 @@ if TYPE_CHECKING:
|
||||
MYSETTING = 1122
|
||||
REGISTRY: Optional['Class'] = None
|
||||
LIST: List[str] = ['1', '2']
|
||||
[/CASE]
|
||||
|
||||
[CASE fail_if_there_is_no_setting]
|
||||
from django.conf import settings
|
||||
reveal_type(settings.NOT_EXISTING)
|
||||
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[disable_cache]
|
||||
[file mysettings.py]
|
||||
[out]
|
||||
main:2: error: Revealed type is 'Any'
|
||||
main:2: error: "LazySettings" has no attribute "NOT_EXISTING"
|
||||
main:2: error: "LazySettings" has no attribute "NOT_EXISTING"
|
||||
[/CASE]
|
||||
@@ -11,9 +11,11 @@ reveal_type(get_object_or_404(MyModel.objects.get_queryset())) # E: Revealed ty
|
||||
reveal_type(get_list_or_404(MyModel)) # E: Revealed type is 'builtins.list[main.MyModel*]'
|
||||
reveal_type(get_list_or_404(MyModel.objects)) # E: Revealed type is 'builtins.list[main.MyModel*]'
|
||||
reveal_type(get_list_or_404(MyModel.objects.get_queryset())) # E: Revealed type is 'builtins.list[main.MyModel*]'
|
||||
[out]
|
||||
[/CASE]
|
||||
|
||||
[CASE get_user_model_returns_proper_class]
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[disable_cache]
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from myapp.models import MyUser
|
||||
@@ -22,7 +24,6 @@ from django.contrib.auth import get_user_model
|
||||
UserModel = get_user_model()
|
||||
reveal_type(UserModel.objects) # E: Revealed type is 'django.db.models.manager.Manager[myapp.models.MyUser]'
|
||||
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[file mysettings.py]
|
||||
INSTALLED_APPS = ('myapp',)
|
||||
AUTH_USER_MODEL = 'myapp.MyUser'
|
||||
@@ -32,15 +33,16 @@ AUTH_USER_MODEL = 'myapp.MyUser'
|
||||
from django.db import models
|
||||
class MyUser(models.Model):
|
||||
pass
|
||||
[out]
|
||||
[/CASE]
|
||||
|
||||
[CASE return_type_model_and_show_error_if_model_not_yet_imported]
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[disable_cache]
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
UserModel = get_user_model()
|
||||
reveal_type(UserModel.objects)
|
||||
|
||||
[env DJANGO_SETTINGS_MODULE=mysettings]
|
||||
[file mysettings.py]
|
||||
INSTALLED_APPS = ('myapp',)
|
||||
AUTH_USER_MODEL = 'myapp.MyUser'
|
||||
@@ -53,4 +55,5 @@ class MyUser(models.Model):
|
||||
[out]
|
||||
main:3: error: "myapp.MyUser" model class is not imported so far. Try to import it (under if TYPE_CHECKING) at the beginning of the current file
|
||||
main:4: error: Revealed type is 'Any'
|
||||
main:4: error: "Type[Model]" has no attribute "objects"
|
||||
main:4: error: "Type[Model]" has no attribute "objects"
|
||||
[/CASE]
|
||||
|
||||
50
test-data/typecheck/transaction.test
Normal file
50
test-data/typecheck/transaction.test
Normal file
@@ -0,0 +1,50 @@
|
||||
[CASE test_transaction_atomic]
|
||||
|
||||
from django.db import transaction
|
||||
|
||||
with transaction.atomic():
|
||||
pass
|
||||
|
||||
with transaction.atomic(using="mydb"):
|
||||
pass
|
||||
|
||||
with transaction.atomic(using="mydb", savepoint=False):
|
||||
pass
|
||||
|
||||
@transaction.atomic()
|
||||
def decorated_func(param1: str, param2: int) -> bool:
|
||||
pass
|
||||
|
||||
# Ensure that the function's type is preserved
|
||||
reveal_type(decorated_func) # E: Revealed type is 'def (param1: builtins.str, param2: builtins.int) -> builtins.bool'
|
||||
|
||||
@transaction.atomic(using="mydb")
|
||||
def decorated_func_using(param1: str, param2: int) -> bool:
|
||||
pass
|
||||
|
||||
# Ensure that the function's type is preserved
|
||||
reveal_type(decorated_func_using) # E: Revealed type is 'def (param1: builtins.str, param2: builtins.int) -> builtins.bool'
|
||||
|
||||
class ClassWithAtomicMethod:
|
||||
# Bare decorator
|
||||
@transaction.atomic
|
||||
def atomic_method1(self, abc: int) -> str:
|
||||
pass
|
||||
|
||||
@transaction.atomic(savepoint=True)
|
||||
def atomic_method2(self):
|
||||
pass
|
||||
|
||||
@transaction.atomic(using="db", savepoint=True)
|
||||
def atomic_method3(self, myparam: str) -> int:
|
||||
pass
|
||||
|
||||
ClassWithAtomicMethod().atomic_method1("abc") # E: Argument 1 to "atomic_method1" of "ClassWithAtomicMethod" has incompatible type "str"; expected "int"
|
||||
|
||||
# Ensure that the method's type is preserved
|
||||
reveal_type(ClassWithAtomicMethod().atomic_method1) # E: Revealed type is 'def (abc: builtins.int) -> builtins.str'
|
||||
|
||||
# Ensure that the method's type is preserved
|
||||
reveal_type(ClassWithAtomicMethod().atomic_method3) # E: Revealed type is 'def (myparam: builtins.str) -> builtins.int'
|
||||
|
||||
[out]
|
||||
Reference in New Issue
Block a user