mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-12 15:01:55 +08:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3d76f9a1e | ||
|
|
fde071b883 | ||
|
|
324b961d74 | ||
|
|
86c63d790b | ||
|
|
050c1b8887 | ||
|
|
8978ad471f | ||
|
|
f7dfbefbd6 | ||
|
|
627daa55f5 | ||
|
|
194489ee8d | ||
|
|
1d2c7fb805 | ||
|
|
18c908bf98 | ||
|
|
e0e8814804 | ||
|
|
53f5d2214b | ||
|
|
9e4ed70fc5 | ||
|
|
18445f686f | ||
|
|
c962b8ac68 | ||
|
|
70c3126348 | ||
|
|
af8ecc5520 |
22
.travis.yml
22
.travis.yml
@@ -4,20 +4,34 @@ dist: xenial
|
|||||||
sudo: required
|
sudo: required
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- name: Typecheck Django test suite
|
|
||||||
python: 3.7
|
|
||||||
script: 'python ./scripts/typecheck_tests.py'
|
|
||||||
|
|
||||||
- name: Run plugin test suite with python 3.7
|
- name: Run plugin test suite with python 3.7
|
||||||
python: 3.7
|
python: 3.7
|
||||||
script: |
|
script: |
|
||||||
set -e
|
set -e
|
||||||
pytest
|
pytest
|
||||||
|
|
||||||
|
- name: Run plugin test suite with python 3.6
|
||||||
|
python: 3.6
|
||||||
|
script: |
|
||||||
|
set -e
|
||||||
|
pytest
|
||||||
|
|
||||||
|
- name: Typecheck Django test suite
|
||||||
|
python: 3.7
|
||||||
|
script: 'python ./scripts/typecheck_tests.py'
|
||||||
|
|
||||||
- name: Lint with black
|
- name: Lint with black
|
||||||
python: 3.7
|
python: 3.7
|
||||||
script: 'black --check --line-length=120 django-stubs/'
|
script: 'black --check --line-length=120 django-stubs/'
|
||||||
|
|
||||||
|
- name: Lint plugin code with flake8
|
||||||
|
python: 3.7
|
||||||
|
script: 'flake8'
|
||||||
|
|
||||||
|
- name: Lint plugin code with isort
|
||||||
|
python: 3.7
|
||||||
|
script: 'isort --check'
|
||||||
|
|
||||||
before_install: |
|
before_install: |
|
||||||
# Upgrade pip, setuptools, and wheel
|
# Upgrade pip, setuptools, and wheel
|
||||||
pip install -U pip setuptools wheel
|
pip install -U pip setuptools wheel
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
black
|
black
|
||||||
pytest-mypy-plugins
|
pytest-mypy-plugins
|
||||||
|
flake8
|
||||||
|
isort==4.3.4
|
||||||
-e .
|
-e .
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from django.db.models.query import QuerySet
|
|||||||
|
|
||||||
_T = TypeVar("_T", bound=Model, covariant=True)
|
_T = TypeVar("_T", bound=Model, covariant=True)
|
||||||
|
|
||||||
class BaseManager(QuerySet[_T]):
|
class BaseManager(QuerySet[_T, _T]):
|
||||||
creation_counter: int = ...
|
creation_counter: int = ...
|
||||||
auto_created: bool = ...
|
auto_created: bool = ...
|
||||||
use_in_migrations: bool = ...
|
use_in_migrations: bool = ...
|
||||||
@@ -21,7 +21,7 @@ class BaseManager(QuerySet[_T]):
|
|||||||
def _get_queryset_methods(cls, queryset_class: type) -> Dict[str, Any]: ...
|
def _get_queryset_methods(cls, queryset_class: type) -> Dict[str, Any]: ...
|
||||||
def contribute_to_class(self, model: Type[Model], name: str) -> None: ...
|
def contribute_to_class(self, model: Type[Model], name: str) -> None: ...
|
||||||
def db_manager(self, using: Optional[str] = ..., hints: Optional[Dict[str, Model]] = ...) -> Manager: ...
|
def db_manager(self, using: Optional[str] = ..., hints: Optional[Dict[str, Model]] = ...) -> Manager: ...
|
||||||
def get_queryset(self) -> QuerySet[_T]: ...
|
def get_queryset(self) -> QuerySet[_T, _T]: ...
|
||||||
|
|
||||||
class Manager(BaseManager[_T]): ...
|
class Manager(BaseManager[_T]): ...
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
Dict,
|
Dict,
|
||||||
@@ -13,6 +14,9 @@ from typing import (
|
|||||||
TypeVar,
|
TypeVar,
|
||||||
Union,
|
Union,
|
||||||
overload,
|
overload,
|
||||||
|
Generic,
|
||||||
|
NamedTuple,
|
||||||
|
Collection,
|
||||||
)
|
)
|
||||||
|
|
||||||
from django.db.models.base import Model
|
from django.db.models.base import Model
|
||||||
@@ -46,7 +50,7 @@ class FlatValuesListIterable(BaseIterable):
|
|||||||
|
|
||||||
_T = TypeVar("_T", bound=models.Model, covariant=True)
|
_T = TypeVar("_T", bound=models.Model, covariant=True)
|
||||||
|
|
||||||
class QuerySet(Iterable[_T], Sized):
|
class QuerySet(Generic[_T, _Row], Collection[_Row], Sized):
|
||||||
query: Query
|
query: Query
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -58,32 +62,33 @@ class QuerySet(Iterable[_T], Sized):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def as_manager(cls) -> Manager[Any]: ...
|
def as_manager(cls) -> Manager[Any]: ...
|
||||||
def __len__(self) -> int: ...
|
def __len__(self) -> int: ...
|
||||||
def __iter__(self) -> Iterator[_T]: ...
|
def __iter__(self) -> Iterator[_Row]: ...
|
||||||
|
def __contains__(self, x: object) -> bool: ...
|
||||||
|
@overload
|
||||||
|
def __getitem__(self, i: int) -> _Row: ...
|
||||||
|
@overload
|
||||||
|
def __getitem__(self, s: slice) -> QuerySet[_T, _Row]: ...
|
||||||
def __bool__(self) -> bool: ...
|
def __bool__(self) -> bool: ...
|
||||||
def __class_getitem__(cls, item: Type[_T]):
|
def __class_getitem__(cls, item: Type[_T]):
|
||||||
pass
|
pass
|
||||||
def __getstate__(self) -> Dict[str, Any]: ...
|
def __getstate__(self) -> Dict[str, Any]: ...
|
||||||
@overload
|
# __and__ and __or__ ignore the other QuerySet's _Row type parameter because they use the same row type as the self QuerySet.
|
||||||
def __getitem__(self, k: int) -> _T: ...
|
# Technically, the other QuerySet must be of the same type _T, but _T is covariant
|
||||||
@overload
|
def __and__(self, other: QuerySet[_T, Any]) -> QuerySet[_T, _Row]: ...
|
||||||
def __getitem__(self, k: str) -> Any: ...
|
def __or__(self, other: QuerySet[_T, Any]) -> QuerySet[_T, _Row]: ...
|
||||||
@overload
|
def iterator(self, chunk_size: int = ...) -> Iterator[_Row]: ...
|
||||||
def __getitem__(self, k: slice) -> QuerySet[_T]: ...
|
|
||||||
def __and__(self, other: QuerySet) -> QuerySet: ...
|
|
||||||
def __or__(self, other: QuerySet) -> QuerySet: ...
|
|
||||||
def iterator(self, chunk_size: int = ...) -> Iterator[_T]: ...
|
|
||||||
def aggregate(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: ...
|
def aggregate(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: ...
|
||||||
def get(self, *args: Any, **kwargs: Any) -> _T: ...
|
def get(self, *args: Any, **kwargs: Any) -> _Row: ...
|
||||||
def create(self, **kwargs: Any) -> _T: ...
|
def create(self, **kwargs: Any) -> _T: ...
|
||||||
def bulk_create(self, objs: Iterable[Model], batch_size: Optional[int] = ...) -> List[_T]: ...
|
def bulk_create(self, objs: Iterable[Model], batch_size: Optional[int] = ...) -> List[_T]: ...
|
||||||
def get_or_create(self, defaults: Optional[MutableMapping[str, Any]] = ..., **kwargs: Any) -> Tuple[_T, bool]: ...
|
def get_or_create(self, defaults: Optional[MutableMapping[str, Any]] = ..., **kwargs: Any) -> Tuple[_T, bool]: ...
|
||||||
def update_or_create(
|
def update_or_create(
|
||||||
self, defaults: Optional[MutableMapping[str, Any]] = ..., **kwargs: Any
|
self, defaults: Optional[MutableMapping[str, Any]] = ..., **kwargs: Any
|
||||||
) -> Tuple[_T, bool]: ...
|
) -> Tuple[_T, bool]: ...
|
||||||
def earliest(self, *fields: Any, field_name: Optional[Any] = ...) -> _T: ...
|
def earliest(self, *fields: Any, field_name: Optional[Any] = ...) -> _Row: ...
|
||||||
def latest(self, *fields: Any, field_name: Optional[Any] = ...) -> _T: ...
|
def latest(self, *fields: Any, field_name: Optional[Any] = ...) -> _Row: ...
|
||||||
def first(self) -> Optional[_T]: ...
|
def first(self) -> Optional[_Row]: ...
|
||||||
def last(self) -> Optional[_T]: ...
|
def last(self) -> Optional[_Row]: ...
|
||||||
def in_bulk(self, id_list: Iterable[Any] = ..., *, field_name: str = ...) -> Dict[Any, _T]: ...
|
def in_bulk(self, id_list: Iterable[Any] = ..., *, field_name: str = ...) -> Dict[Any, _T]: ...
|
||||||
def delete(self) -> Tuple[int, Dict[str, int]]: ...
|
def delete(self) -> Tuple[int, Dict[str, int]]: ...
|
||||||
def update(self, **kwargs: Any) -> int: ...
|
def update(self, **kwargs: Any) -> int: ...
|
||||||
@@ -93,31 +98,38 @@ class QuerySet(Iterable[_T], Sized):
|
|||||||
def raw(
|
def raw(
|
||||||
self, raw_query: str, params: Any = ..., translations: Optional[Dict[str, str]] = ..., using: None = ...
|
self, raw_query: str, params: Any = ..., translations: Optional[Dict[str, str]] = ..., using: None = ...
|
||||||
) -> RawQuerySet: ...
|
) -> RawQuerySet: ...
|
||||||
def values(self, *fields: Union[str, Combinable], **expressions: Any) -> QuerySet: ...
|
def values(self, *fields: Union[str, Combinable], **expressions: Any) -> QuerySet[_T, Dict[str, Any]]: ...
|
||||||
def values_list(self, *fields: Union[str, Combinable], flat: bool = ..., named: bool = ...) -> QuerySet: ...
|
@overload
|
||||||
# @overload
|
def values_list(
|
||||||
# def values_list(self, *fields: Union[str, Combinable], named: Literal[True]) -> NamedValuesListIterable: ...
|
self, *fields: Union[str, Combinable], flat: Literal[False] = ..., named: Literal[True]
|
||||||
# @overload
|
) -> QuerySet[_T, NamedTuple]: ...
|
||||||
# def values_list(self, *fields: Union[str, Combinable], flat: Literal[True]) -> FlatValuesListIterable: ...
|
@overload
|
||||||
# @overload
|
def values_list(
|
||||||
# def values_list(self, *fields: Union[str, Combinable]) -> ValuesListIterable: ...
|
self, *fields: Union[str, Combinable], flat: Literal[True], named: Literal[False] = ...
|
||||||
def dates(self, field_name: str, kind: str, order: str = ...) -> QuerySet: ...
|
) -> QuerySet[_T, Any]: ...
|
||||||
def datetimes(self, field_name: str, kind: str, order: str = ..., tzinfo: None = ...) -> QuerySet: ...
|
@overload
|
||||||
def none(self) -> QuerySet[_T]: ...
|
def values_list(
|
||||||
def all(self) -> QuerySet[_T]: ...
|
self, *fields: Union[str, Combinable], flat: Literal[False] = ..., named: Literal[False] = ...
|
||||||
def filter(self, *args: Any, **kwargs: Any) -> QuerySet[_T]: ...
|
) -> QuerySet[_T, Tuple]: ...
|
||||||
def exclude(self, *args: Any, **kwargs: Any) -> QuerySet[_T]: ...
|
def dates(self, field_name: str, kind: str, order: str = ...) -> QuerySet[_T, datetime.date]: ...
|
||||||
def complex_filter(self, filter_obj: Any) -> QuerySet[_T]: ...
|
def datetimes(
|
||||||
|
self, field_name: str, kind: str, order: str = ..., tzinfo: None = ...
|
||||||
|
) -> QuerySet[_T, datetime.datetime]: ...
|
||||||
|
def none(self) -> QuerySet[_T, _Row]: ...
|
||||||
|
def all(self) -> QuerySet[_T, _Row]: ...
|
||||||
|
def filter(self, *args: Any, **kwargs: Any) -> QuerySet[_T, _Row]: ...
|
||||||
|
def exclude(self, *args: Any, **kwargs: Any) -> QuerySet[_T, _Row]: ...
|
||||||
|
def complex_filter(self, filter_obj: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def count(self) -> int: ...
|
def count(self) -> int: ...
|
||||||
def union(self, *other_qs: Any, all: bool = ...) -> QuerySet[_T]: ...
|
def union(self, *other_qs: Any, all: bool = ...) -> QuerySet[_T, _Row]: ...
|
||||||
def intersection(self, *other_qs: Any) -> QuerySet[_T]: ...
|
def intersection(self, *other_qs: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def difference(self, *other_qs: Any) -> QuerySet[_T]: ...
|
def difference(self, *other_qs: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def select_for_update(self, nowait: bool = ..., skip_locked: bool = ..., of: Tuple = ...) -> QuerySet: ...
|
def select_for_update(self, nowait: bool = ..., skip_locked: bool = ..., of: Tuple = ...) -> QuerySet[_T, _Row]: ...
|
||||||
def select_related(self, *fields: Any) -> QuerySet[_T]: ...
|
def select_related(self, *fields: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def prefetch_related(self, *lookups: Any) -> QuerySet[_T]: ...
|
def prefetch_related(self, *lookups: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def annotate(self, *args: Any, **kwargs: Any) -> QuerySet[_T]: ...
|
def annotate(self, *args: Any, **kwargs: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def order_by(self, *field_names: Any) -> QuerySet[_T]: ...
|
def order_by(self, *field_names: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def distinct(self, *field_names: Any) -> QuerySet[_T]: ...
|
def distinct(self, *field_names: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def extra(
|
def extra(
|
||||||
self,
|
self,
|
||||||
select: Optional[Dict[str, Any]] = ...,
|
select: Optional[Dict[str, Any]] = ...,
|
||||||
@@ -126,11 +138,11 @@ class QuerySet(Iterable[_T], Sized):
|
|||||||
tables: Optional[List[str]] = ...,
|
tables: Optional[List[str]] = ...,
|
||||||
order_by: Optional[Sequence[str]] = ...,
|
order_by: Optional[Sequence[str]] = ...,
|
||||||
select_params: Optional[Sequence[Any]] = ...,
|
select_params: Optional[Sequence[Any]] = ...,
|
||||||
) -> QuerySet[_T]: ...
|
) -> QuerySet[_T, _Row]: ...
|
||||||
def reverse(self) -> QuerySet[_T]: ...
|
def reverse(self) -> QuerySet[_T, _Row]: ...
|
||||||
def defer(self, *fields: Any) -> QuerySet[_T]: ...
|
def defer(self, *fields: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def only(self, *fields: Any) -> QuerySet[_T]: ...
|
def only(self, *fields: Any) -> QuerySet[_T, _Row]: ...
|
||||||
def using(self, alias: Optional[str]) -> QuerySet[_T]: ...
|
def using(self, alias: Optional[str]) -> QuerySet[_T, _Row]: ...
|
||||||
@property
|
@property
|
||||||
def ordered(self) -> bool: ...
|
def ordered(self) -> bool: ...
|
||||||
@property
|
@property
|
||||||
@@ -159,7 +171,7 @@ class RawQuerySet(Iterable[_T], Sized):
|
|||||||
@overload
|
@overload
|
||||||
def __getitem__(self, k: str) -> Any: ...
|
def __getitem__(self, k: str) -> Any: ...
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(self, k: slice) -> QuerySet[_T]: ...
|
def __getitem__(self, k: slice) -> RawQuerySet[_T]: ...
|
||||||
@property
|
@property
|
||||||
def columns(self) -> List[str]: ...
|
def columns(self) -> List[str]: ...
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ def redirect(
|
|||||||
|
|
||||||
_T = TypeVar("_T", bound=Model)
|
_T = TypeVar("_T", bound=Model)
|
||||||
|
|
||||||
def get_object_or_404(klass: Union[Type[_T], Manager[_T], QuerySet[_T]], *args: Any, **kwargs: Any) -> _T: ...
|
def get_object_or_404(klass: Union[Type[_T], Manager[_T], QuerySet[_T, _T]], *args: Any, **kwargs: Any) -> _T: ...
|
||||||
def get_list_or_404(klass: Union[Type[_T], Manager[_T], QuerySet[_T]], *args: Any, **kwargs: Any) -> List[_T]: ...
|
def get_list_or_404(klass: Union[Type[_T], Manager[_T], QuerySet[_T, _T]], *args: Any, **kwargs: Any) -> List[_T]: ...
|
||||||
def resolve_url(to: Union[Callable, Model, str], *args: Any, **kwargs: Any) -> str: ...
|
def resolve_url(to: Union[Callable, Model, str], *args: Any, **kwargs: Any) -> str: ...
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ from typing import (
|
|||||||
Union,
|
Union,
|
||||||
overload,
|
overload,
|
||||||
Iterator,
|
Iterator,
|
||||||
|
Optional,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from typing_extensions import Literal
|
||||||
|
|
||||||
_K = TypeVar("_K")
|
_K = TypeVar("_K")
|
||||||
_V = TypeVar("_V")
|
_V = TypeVar("_V")
|
||||||
|
|
||||||
@@ -27,24 +30,22 @@ class OrderedSet(MutableSet[_K]):
|
|||||||
|
|
||||||
class MultiValueDictKeyError(KeyError): ...
|
class MultiValueDictKeyError(KeyError): ...
|
||||||
|
|
||||||
_Val = Union[_V, List[_V]]
|
|
||||||
|
|
||||||
class MultiValueDict(MutableMapping[_K, _V]):
|
class MultiValueDict(MutableMapping[_K, _V]):
|
||||||
@overload
|
@overload
|
||||||
def __init__(self, key_to_list_mapping: Iterable[Tuple[_K, _Val]] = ...) -> None: ...
|
def __init__(self, key_to_list_mapping: Mapping[_K, Optional[List[_V]]] = ...) -> None: ...
|
||||||
@overload
|
@overload
|
||||||
def __init__(self, key_to_list_mapping: Mapping[_K, _Val] = ...) -> None: ...
|
def __init__(self, key_to_list_mapping: Iterable[Tuple[_K, List[_V]]] = ...) -> None: ...
|
||||||
def getlist(self, key: _K, default: List[_V] = None) -> List[_V]: ...
|
def getlist(self, key: _K, default: List[_V] = None) -> List[_V]: ...
|
||||||
def setlist(self, key: _K, list_: List[_V]) -> None: ...
|
def setlist(self, key: _K, list_: List[_V]) -> None: ...
|
||||||
def setlistdefault(self, key: _K, default_list: List[_V] = None) -> List[_V]: ...
|
def setlistdefault(self, key: _K, default_list: List[_V] = None) -> List[_V]: ...
|
||||||
def appendlist(self, key: _K, value: _V) -> None: ...
|
def appendlist(self, key: _K, value: _V) -> None: ...
|
||||||
def lists(self) -> Iterable[Tuple[_K, List[_V]]]: ...
|
def lists(self) -> Iterable[Tuple[_K, List[_V]]]: ...
|
||||||
def dict(self) -> Dict[_K, _Val]: ...
|
def dict(self) -> Dict[_K, Union[_V, List[_V]]]: ...
|
||||||
def copy(self) -> MultiValueDict[_K, _V]: ...
|
def copy(self) -> MultiValueDict[_K, _V]: ...
|
||||||
# These overrides are needed to convince mypy that this isn't an abstract class
|
# These overrides are needed to convince mypy that this isn't an abstract class
|
||||||
def __delitem__(self, item: _K) -> None: ...
|
def __delitem__(self, item: _K) -> None: ...
|
||||||
def __getitem__(self, item: _K) -> _Val: ... # type: ignore
|
def __getitem__(self, item: _K) -> Union[_V, Literal[[]]]: ... # type: ignore
|
||||||
def __setitem__(self, k: _K, v: _Val) -> None: ...
|
def __setitem__(self, k: _K, v: Union[_V, List[_V]]) -> None: ...
|
||||||
def __len__(self) -> int: ...
|
def __len__(self) -> int: ...
|
||||||
def __iter__(self) -> Iterator[_K]: ...
|
def __iter__(self) -> Iterator[_K]: ...
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,10 @@
|
|||||||
from typing import Any, Callable, Optional, Set, Tuple, Type, Union
|
from typing import Any, Callable, Optional, Set, Tuple, Type, Union
|
||||||
|
|
||||||
from django.contrib.auth.mixins import AccessMixin
|
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
|
||||||
from django.middleware.cache import CacheMiddleware
|
from django.middleware.cache import CacheMiddleware
|
||||||
from django.test.testcases import LiveServerTestCase
|
from django.test.testcases import LiveServerTestCase
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
from django.views.generic.base import TemplateResponseMixin, View
|
|
||||||
|
|
||||||
class classonlymethod(classmethod):
|
class classonlymethod(classmethod): ...
|
||||||
def __get__(
|
|
||||||
self,
|
|
||||||
instance: Optional[View],
|
|
||||||
cls: Type[Union[AccessMixin, SuccessMessageMixin, TemplateResponseMixin, View]] = ...,
|
|
||||||
) -> Callable: ...
|
|
||||||
|
|
||||||
def method_decorator(
|
def method_decorator(
|
||||||
decorator: Union[Callable, Set[Callable], Tuple[Callable, Callable]], name: str = ...
|
decorator: Union[Callable, Set[Callable], Tuple[Callable, Callable]], name: str = ...
|
||||||
|
|||||||
@@ -1,144 +1,106 @@
|
|||||||
import types
|
from __future__ import print_function
|
||||||
from typing import Any, Optional
|
|
||||||
|
|
||||||
PY2: Any
|
import types
|
||||||
PY3: Any
|
import typing
|
||||||
PY34: Any
|
import unittest
|
||||||
string_types: Any
|
from typing import (
|
||||||
integer_types: Any
|
Any,
|
||||||
class_types: Any
|
AnyStr,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
ItemsView,
|
||||||
|
Iterable,
|
||||||
|
KeysView,
|
||||||
|
Mapping,
|
||||||
|
NoReturn,
|
||||||
|
Optional,
|
||||||
|
Pattern,
|
||||||
|
Text,
|
||||||
|
Tuple,
|
||||||
|
Type,
|
||||||
|
TypeVar,
|
||||||
|
Union,
|
||||||
|
ValuesView,
|
||||||
|
overload,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Exports
|
||||||
|
|
||||||
|
_T = TypeVar("_T")
|
||||||
|
_K = TypeVar("_K")
|
||||||
|
_V = TypeVar("_V")
|
||||||
|
|
||||||
|
# TODO make constant, then move this stub to 2and3
|
||||||
|
# https://github.com/python/typeshed/issues/17
|
||||||
|
PY2 = False
|
||||||
|
PY3 = True
|
||||||
|
PY34 = ... # type: bool
|
||||||
|
|
||||||
|
string_types = (str,)
|
||||||
|
integer_types = (int,)
|
||||||
|
class_types = (type,)
|
||||||
text_type = str
|
text_type = str
|
||||||
binary_type = bytes
|
binary_type = bytes
|
||||||
MAXSIZE: Any
|
|
||||||
text_type = unicode
|
|
||||||
binary_type = str
|
|
||||||
|
|
||||||
class X:
|
MAXSIZE = ... # type: int
|
||||||
def __len__(self): ...
|
|
||||||
|
|
||||||
class _LazyDescr:
|
# def add_move
|
||||||
name: Any = ...
|
# def remove_move
|
||||||
def __init__(self, name: Any) -> None: ...
|
|
||||||
def __get__(self, obj: Any, tp: Any): ...
|
|
||||||
|
|
||||||
class MovedModule(_LazyDescr):
|
def callable(obj: object) -> bool: ...
|
||||||
mod: Any = ...
|
def get_unbound_function(unbound: types.FunctionType) -> types.FunctionType: ...
|
||||||
def __init__(self, name: Any, old: Any, new: Optional[Any] = ...) -> None: ...
|
def create_bound_method(func: types.FunctionType, obj: object) -> types.MethodType: ...
|
||||||
def __getattr__(self, attr: Any): ...
|
def create_unbound_method(func: types.FunctionType, cls: type) -> types.FunctionType: ...
|
||||||
|
|
||||||
class _LazyModule(types.ModuleType):
|
|
||||||
__doc__: Any = ...
|
|
||||||
def __init__(self, name: Any) -> None: ...
|
|
||||||
def __dir__(self): ...
|
|
||||||
|
|
||||||
class MovedAttribute(_LazyDescr):
|
|
||||||
mod: Any = ...
|
|
||||||
attr: Any = ...
|
|
||||||
def __init__(
|
|
||||||
self, name: Any, old_mod: Any, new_mod: Any, old_attr: Optional[Any] = ..., new_attr: Optional[Any] = ...
|
|
||||||
) -> None: ...
|
|
||||||
|
|
||||||
class _SixMetaPathImporter:
|
|
||||||
name: Any = ...
|
|
||||||
known_modules: Any = ...
|
|
||||||
def __init__(self, six_module_name: Any) -> None: ...
|
|
||||||
def find_module(self, fullname: Any, path: Optional[Any] = ...): ...
|
|
||||||
def load_module(self, fullname: Any): ...
|
|
||||||
def is_package(self, fullname: Any): ...
|
|
||||||
def get_code(self, fullname: Any): ...
|
|
||||||
get_source: Any = ...
|
|
||||||
|
|
||||||
class _MovedItems(_LazyModule):
|
|
||||||
__path__: Any = ...
|
|
||||||
|
|
||||||
moves: Any
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_parse(_LazyModule): ...
|
|
||||||
class Module_six_moves_urllib_error(_LazyModule): ...
|
|
||||||
class Module_six_moves_urllib_request(_LazyModule): ...
|
|
||||||
class Module_six_moves_urllib_response(_LazyModule): ...
|
|
||||||
class Module_six_moves_urllib_robotparser(_LazyModule): ...
|
|
||||||
|
|
||||||
class Module_six_moves_urllib(types.ModuleType):
|
|
||||||
__path__: Any = ...
|
|
||||||
parse: Any = ...
|
|
||||||
error: Any = ...
|
|
||||||
request: Any = ...
|
|
||||||
response: Any = ...
|
|
||||||
robotparser: Any = ...
|
|
||||||
def __dir__(self): ...
|
|
||||||
|
|
||||||
def add_move(move: Any) -> None: ...
|
|
||||||
def remove_move(name: Any) -> None: ...
|
|
||||||
|
|
||||||
advance_iterator = next
|
|
||||||
next = advance_iterator
|
|
||||||
callable = callable
|
|
||||||
|
|
||||||
def get_unbound_function(unbound: Any): ...
|
|
||||||
|
|
||||||
create_bound_method: Any
|
|
||||||
|
|
||||||
def create_unbound_method(func: Any, cls: Any): ...
|
|
||||||
|
|
||||||
Iterator = object
|
Iterator = object
|
||||||
|
|
||||||
class Iterator:
|
def get_method_function(meth: types.MethodType) -> types.FunctionType: ...
|
||||||
def next(self): ...
|
def get_method_self(meth: types.MethodType) -> Optional[object]: ...
|
||||||
|
def get_function_closure(fun: types.FunctionType) -> Optional[Tuple[types._Cell, ...]]: ...
|
||||||
|
def get_function_code(fun: types.FunctionType) -> types.CodeType: ...
|
||||||
|
def get_function_defaults(fun: types.FunctionType) -> Optional[Tuple[Any, ...]]: ...
|
||||||
|
def get_function_globals(fun: types.FunctionType) -> Dict[str, Any]: ...
|
||||||
|
def iterkeys(d: Mapping[_K, _V]) -> typing.Iterator[_K]: ...
|
||||||
|
def itervalues(d: Mapping[_K, _V]) -> typing.Iterator[_V]: ...
|
||||||
|
def iteritems(d: Mapping[_K, _V]) -> typing.Iterator[Tuple[_K, _V]]: ...
|
||||||
|
|
||||||
callable = callable
|
# def iterlists
|
||||||
get_method_function: Any
|
|
||||||
get_method_self: Any
|
|
||||||
get_function_closure: Any
|
|
||||||
get_function_code: Any
|
|
||||||
get_function_defaults: Any
|
|
||||||
get_function_globals: Any
|
|
||||||
|
|
||||||
def iterkeys(d: Any, **kw: Any): ...
|
def viewkeys(d: Mapping[_K, _V]) -> KeysView[_K]: ...
|
||||||
def itervalues(d: Any, **kw: Any): ...
|
def viewvalues(d: Mapping[_K, _V]) -> ValuesView[_V]: ...
|
||||||
def iteritems(d: Any, **kw: Any): ...
|
def viewitems(d: Mapping[_K, _V]) -> ItemsView[_K, _V]: ...
|
||||||
def iterlists(d: Any, **kw: Any): ...
|
def b(s: str) -> binary_type: ...
|
||||||
|
def u(s: str) -> text_type: ...
|
||||||
viewkeys: Any
|
|
||||||
viewvalues: Any
|
|
||||||
viewitems: Any
|
|
||||||
|
|
||||||
def b(s: Any): ...
|
|
||||||
def u(s: Any): ...
|
|
||||||
|
|
||||||
unichr = chr
|
unichr = chr
|
||||||
int2byte: Any
|
|
||||||
byte2int: Any
|
|
||||||
indexbytes: Any
|
|
||||||
iterbytes = iter
|
|
||||||
StringIO: Any
|
|
||||||
BytesIO: Any
|
|
||||||
unichr = unichr
|
|
||||||
int2byte = chr
|
|
||||||
|
|
||||||
def assertCountEqual(self, *args: Any, **kwargs: Any): ...
|
def int2byte(i: int) -> bytes: ...
|
||||||
def assertRaisesRegex(self, *args: Any, **kwargs: Any): ...
|
def byte2int(bs: binary_type) -> int: ...
|
||||||
def assertRegex(self, *args: Any, **kwargs: Any): ...
|
def indexbytes(buf: binary_type, i: int) -> int: ...
|
||||||
|
def iterbytes(buf: binary_type) -> typing.Iterator[int]: ...
|
||||||
|
def assertCountEqual(
|
||||||
|
self: unittest.TestCase, first: Iterable[_T], second: Iterable[_T], msg: Optional[str] = ...
|
||||||
|
) -> None: ...
|
||||||
|
@overload
|
||||||
|
def assertRaisesRegex(self: unittest.TestCase, msg: Optional[str] = ...) -> Any: ...
|
||||||
|
@overload
|
||||||
|
def assertRaisesRegex(self: unittest.TestCase, callable_obj: Callable[..., Any], *args: Any, **kwargs: Any) -> Any: ...
|
||||||
|
def assertRegex(
|
||||||
|
self: unittest.TestCase, text: AnyStr, expected_regex: Union[AnyStr, Pattern[AnyStr]], msg: Optional[str] = ...
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
exec_: Any
|
exec_ = exec
|
||||||
|
|
||||||
def reraise(tp: Any, value: Any, tb: Optional[Any] = ...) -> None: ...
|
def reraise(
|
||||||
def raise_from(value: Any, from_value: Any) -> None: ...
|
tp: Optional[Type[BaseException]], value: Optional[BaseException], tb: Optional[types.TracebackType] = ...
|
||||||
|
) -> NoReturn: ...
|
||||||
|
def raise_from(value: Union[BaseException, Type[BaseException]], from_value: Optional[BaseException]) -> NoReturn: ...
|
||||||
|
|
||||||
print_: Any
|
print_ = print
|
||||||
_print = print_
|
|
||||||
|
|
||||||
def wraps(wrapped: Any, assigned: Any = ..., updated: Any = ...): ...
|
def with_metaclass(meta: type, *bases: type) -> type: ...
|
||||||
|
def add_metaclass(metaclass: type) -> Callable[[_T], _T]: ...
|
||||||
wraps: Any
|
def ensure_binary(s: Union[bytes, Text], encoding: str = ..., errors: str = ...) -> bytes: ...
|
||||||
|
def ensure_str(s: Union[bytes, Text], encoding: str = ..., errors: str = ...) -> str: ...
|
||||||
def with_metaclass(meta: Any, *bases: Any): ...
|
def ensure_text(s: Union[bytes, Text], encoding: str = ..., errors: str = ...) -> Text: ...
|
||||||
def add_metaclass(metaclass: Any): ...
|
def python_2_unicode_compatible(klass: _T) -> _T: ...
|
||||||
def python_2_unicode_compatible(klass: Any): ...
|
|
||||||
|
|
||||||
__path__: Any
|
|
||||||
__package__ = __name__
|
|
||||||
memoryview = memoryview
|
|
||||||
buffer_types: Any
|
|
||||||
memoryview = memoryview
|
|
||||||
memoryview = buffer
|
|
||||||
|
|||||||
5
django-stubs/views/decorators/gzip.pyi
Normal file
5
django-stubs/views/decorators/gzip.pyi
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from typing import Callable, TypeVar
|
||||||
|
|
||||||
|
_C = TypeVar("_C", bound=Callable)
|
||||||
|
|
||||||
|
def gzip_page(view_func: _C) -> _C: ...
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from typing import List, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ class Config:
|
|||||||
fallback=None)
|
fallback=None)
|
||||||
if django_settings:
|
if django_settings:
|
||||||
django_settings = django_settings.strip()
|
django_settings = django_settings.strip()
|
||||||
|
|
||||||
return Config(django_settings_module=django_settings,
|
return Config(django_settings_module=django_settings,
|
||||||
ignore_missing_settings=ini_config.get('mypy_django_plugin', 'ignore_missing_settings',
|
ignore_missing_settings=bool(ini_config.get('mypy_django_plugin', 'ignore_missing_settings',
|
||||||
fallback=False))
|
fallback=False)))
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ import typing
|
|||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from mypy.checker import TypeChecker
|
from mypy.checker import TypeChecker
|
||||||
from mypy.nodes import AssignmentStmt, ClassDef, Expression, ImportedName, Lvalue, MypyFile, NameExpr, SymbolNode, \
|
from mypy.nodes import (
|
||||||
TypeInfo
|
AssignmentStmt, ClassDef, Expression, ImportedName, Lvalue, MypyFile, NameExpr, SymbolNode, TypeInfo,
|
||||||
|
)
|
||||||
from mypy.plugin import FunctionContext, MethodContext
|
from mypy.plugin import FunctionContext, MethodContext
|
||||||
from mypy.types import AnyType, Instance, NoneTyp, Type, TypeOfAny, TypeVarType, UnionType
|
from mypy.types import (
|
||||||
|
AnyType, Instance, NoneTyp, Type, TypeOfAny, TypeVarType, UnionType,
|
||||||
|
)
|
||||||
|
|
||||||
MODEL_CLASS_FULLNAME = 'django.db.models.base.Model'
|
MODEL_CLASS_FULLNAME = 'django.db.models.base.Model'
|
||||||
FIELD_FULLNAME = 'django.db.models.fields.Field'
|
FIELD_FULLNAME = 'django.db.models.fields.Field'
|
||||||
|
|||||||
@@ -1,20 +1,31 @@
|
|||||||
|
from functools import partial
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from typing import Callable, Dict, Optional, Union, cast
|
from typing import Callable, Dict, Optional, Union, cast
|
||||||
|
|
||||||
from mypy.checker import TypeChecker
|
from mypy.checker import TypeChecker
|
||||||
from mypy.nodes import MemberExpr, TypeInfo, NameExpr
|
from mypy.nodes import MemberExpr, NameExpr, TypeInfo
|
||||||
from mypy.options import Options
|
from mypy.options import Options
|
||||||
from mypy.plugin import AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin
|
from mypy.plugin import (
|
||||||
from mypy.types import AnyType, Instance, Type, TypeOfAny, TypeType, UnionType, CallableType, NoneTyp
|
AttributeContext, ClassDefContext, FunctionContext, MethodContext, Plugin,
|
||||||
|
AnalyzeTypeContext)
|
||||||
|
from mypy.types import (
|
||||||
|
AnyType, CallableType, Instance, NoneTyp, Type, TypeOfAny, TypeType, UnionType,
|
||||||
|
)
|
||||||
|
|
||||||
from mypy_django_plugin import helpers, monkeypatch
|
from mypy_django_plugin import helpers, monkeypatch
|
||||||
from mypy_django_plugin.config import Config
|
from mypy_django_plugin.config import Config
|
||||||
from mypy_django_plugin.transformers import fields, init_create
|
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.forms import (
|
||||||
from mypy_django_plugin.transformers.migrations import determine_model_cls_from_string_for_migrations, \
|
make_meta_nested_class_inherit_from_any,
|
||||||
get_string_value_from_expr
|
)
|
||||||
|
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.models import process_model_class
|
||||||
from mypy_django_plugin.transformers.settings import AddSettingValuesToDjangoConfObject, get_settings_metadata
|
from mypy_django_plugin.transformers.settings import (
|
||||||
|
AddSettingValuesToDjangoConfObject, get_settings_metadata,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def transform_model_class(ctx: ClassDefContext) -> None:
|
def transform_model_class(ctx: ClassDefContext) -> None:
|
||||||
@@ -55,15 +66,34 @@ def determine_proper_manager_type(ctx: FunctionContext) -> Type:
|
|||||||
if not isinstance(ret, Instance):
|
if not isinstance(ret, Instance):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
has_manager_base = False
|
||||||
for i, base in enumerate(ret.type.bases):
|
for i, base in enumerate(ret.type.bases):
|
||||||
if base.type.fullname() in {helpers.MANAGER_CLASS_FULLNAME,
|
if base.type.fullname() in {helpers.MANAGER_CLASS_FULLNAME,
|
||||||
helpers.RELATED_MANAGER_CLASS_FULLNAME,
|
helpers.RELATED_MANAGER_CLASS_FULLNAME,
|
||||||
helpers.BASE_MANAGER_CLASS_FULLNAME}:
|
helpers.BASE_MANAGER_CLASS_FULLNAME}:
|
||||||
ret.type.bases[i] = Instance(base.type, [Instance(outer_model_info, [])])
|
has_manager_base = True
|
||||||
return ret
|
break
|
||||||
|
|
||||||
|
if has_manager_base:
|
||||||
|
# Fill in the manager's type argument from the outer model
|
||||||
|
new_type_args = [Instance(outer_model_info, [])]
|
||||||
|
return helpers.reparametrize_instance(ret, new_type_args)
|
||||||
|
else:
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def set_first_generic_param_as_default_for_second(fullname: str, ctx: AnalyzeTypeContext) -> Type:
|
||||||
|
if not ctx.type.args:
|
||||||
|
return ctx.api.named_type(fullname, [AnyType(TypeOfAny.explicit),
|
||||||
|
AnyType(TypeOfAny.explicit)])
|
||||||
|
args = ctx.type.args
|
||||||
|
if len(args) == 1:
|
||||||
|
args = [args[0], args[0]]
|
||||||
|
|
||||||
|
analyzed_args = [ctx.api.analyze_type(arg) for arg in args]
|
||||||
|
return ctx.api.named_type(fullname, analyzed_args)
|
||||||
|
|
||||||
|
|
||||||
def return_user_model_hook(ctx: FunctionContext) -> Type:
|
def return_user_model_hook(ctx: FunctionContext) -> Type:
|
||||||
api = cast(TypeChecker, ctx.api)
|
api = cast(TypeChecker, ctx.api)
|
||||||
setting_expr = helpers.get_setting_expr(api, 'AUTH_USER_MODEL')
|
setting_expr = helpers.get_setting_expr(api, 'AUTH_USER_MODEL')
|
||||||
@@ -250,6 +280,14 @@ class DjangoPlugin(Plugin):
|
|||||||
else:
|
else:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def _get_current_queryset_bases(self) -> Dict[str, int]:
|
||||||
|
model_sym = self.lookup_fully_qualified(helpers.QUERYSET_CLASS_FULLNAME)
|
||||||
|
if model_sym is not None and isinstance(model_sym.node, TypeInfo):
|
||||||
|
return (helpers.get_django_metadata(model_sym.node)
|
||||||
|
.setdefault('queryset_bases', {helpers.QUERYSET_CLASS_FULLNAME: 1}))
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
def get_function_hook(self, fullname: str
|
def get_function_hook(self, fullname: str
|
||||||
) -> Optional[Callable[[FunctionContext], Type]]:
|
) -> Optional[Callable[[FunctionContext], Type]]:
|
||||||
if fullname == 'django.contrib.auth.get_user_model':
|
if fullname == 'django.contrib.auth.get_user_model':
|
||||||
@@ -328,6 +366,14 @@ class DjangoPlugin(Plugin):
|
|||||||
|
|
||||||
return extract_and_return_primary_key_of_bound_related_field_parameter
|
return extract_and_return_primary_key_of_bound_related_field_parameter
|
||||||
|
|
||||||
|
def get_type_analyze_hook(self, fullname: str
|
||||||
|
) -> Optional[Callable[[AnalyzeTypeContext], Type]]:
|
||||||
|
queryset_bases = self._get_current_queryset_bases()
|
||||||
|
if fullname in queryset_bases:
|
||||||
|
return partial(set_first_generic_param_as_default_for_second, fullname)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def plugin(version):
|
def plugin(version):
|
||||||
return DjangoPlugin
|
return DjangoPlugin
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
from .dependencies import (add_modules_as_a_source_seed_files,
|
|
||||||
inject_modules_as_dependencies_for_django_conf_settings,
|
|
||||||
restore_original_load_graph,
|
|
||||||
restore_original_dependencies_handling)
|
|
||||||
@@ -3,9 +3,11 @@ from typing import Optional, cast
|
|||||||
from mypy.checker import TypeChecker
|
from mypy.checker import TypeChecker
|
||||||
from mypy.nodes import ListExpr, NameExpr, StrExpr, TupleExpr, TypeInfo, Var
|
from mypy.nodes import ListExpr, NameExpr, StrExpr, TupleExpr, TypeInfo, Var
|
||||||
from mypy.plugin import FunctionContext
|
from mypy.plugin import FunctionContext
|
||||||
from mypy.types import AnyType, CallableType, Instance, TupleType, Type, TypeOfAny, UnionType
|
from mypy.types import (
|
||||||
|
AnyType, CallableType, Instance, TupleType, Type, TypeOfAny, UnionType,
|
||||||
|
)
|
||||||
|
|
||||||
from mypy_django_plugin import helpers
|
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]:
|
def extract_referred_to_type(ctx: FunctionContext) -> Optional[Instance]:
|
||||||
@@ -99,10 +101,6 @@ def get_private_descriptor_type(type_info: TypeInfo, private_field_name: str, is
|
|||||||
def set_descriptor_types_for_field(ctx: FunctionContext) -> Instance:
|
def set_descriptor_types_for_field(ctx: FunctionContext) -> Instance:
|
||||||
default_return_type = cast(Instance, ctx.default_return_type)
|
default_return_type = cast(Instance, ctx.default_return_type)
|
||||||
is_nullable = helpers.parse_bool(helpers.get_argument_by_name(ctx, 'null'))
|
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',
|
set_type = get_private_descriptor_type(default_return_type.type, '_pyi_private_set_type',
|
||||||
is_nullable=is_nullable)
|
is_nullable=is_nullable)
|
||||||
get_type = get_private_descriptor_type(default_return_type.type, '_pyi_private_get_type',
|
get_type = get_private_descriptor_type(default_return_type.type, '_pyi_private_get_type',
|
||||||
@@ -154,7 +152,7 @@ def record_field_properties_into_outer_model_class(ctx: FunctionContext) -> None
|
|||||||
return
|
return
|
||||||
|
|
||||||
field_name = None
|
field_name = None
|
||||||
for name_expr, stmt in iter_over_assignments(outer_model.defn):
|
for name_expr, stmt in helpers.iter_over_assignments(outer_model.defn):
|
||||||
if stmt == ctx.context and isinstance(name_expr, NameExpr):
|
if stmt == ctx.context and isinstance(name_expr, NameExpr):
|
||||||
field_name = name_expr.name
|
field_name = name_expr.name
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from mypy.plugin import ClassDefContext
|
from mypy.plugin import ClassDefContext
|
||||||
|
|
||||||
from mypy_django_plugin import helpers
|
from mypy_django_plugin import helpers
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ from mypy.checker import TypeChecker
|
|||||||
from mypy.nodes import TypeInfo, Var
|
from mypy.nodes import TypeInfo, Var
|
||||||
from mypy.plugin import FunctionContext, MethodContext
|
from mypy.plugin import FunctionContext, MethodContext
|
||||||
from mypy.types import AnyType, Instance, Type, TypeOfAny
|
from mypy.types import AnyType, Instance, Type, TypeOfAny
|
||||||
|
|
||||||
from mypy_django_plugin import helpers
|
from mypy_django_plugin import helpers
|
||||||
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
|
from mypy_django_plugin.transformers.fields import get_private_descriptor_type
|
||||||
|
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ def redefine_and_typecheck_model_create(ctx: MethodContext) -> Type:
|
|||||||
|
|
||||||
|
|
||||||
def extract_choices_type(model: TypeInfo, field_name: str) -> Optional[str]:
|
def extract_choices_type(model: TypeInfo, field_name: str) -> Optional[str]:
|
||||||
field_metadata = get_fields_metadata(model).get(field_name, {})
|
field_metadata = helpers.get_fields_metadata(model).get(field_name, {})
|
||||||
if 'choices' in field_metadata:
|
if 'choices' in field_metadata:
|
||||||
return field_metadata['choices']
|
return field_metadata['choices']
|
||||||
return None
|
return None
|
||||||
@@ -117,7 +117,7 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
|
|||||||
api = cast(TypeChecker, ctx.api)
|
api = cast(TypeChecker, ctx.api)
|
||||||
|
|
||||||
expected_types: Dict[str, Type] = {}
|
expected_types: Dict[str, Type] = {}
|
||||||
primary_key_type = extract_explicit_set_type_of_model_primary_key(model)
|
primary_key_type = helpers.extract_explicit_set_type_of_model_primary_key(model)
|
||||||
if not primary_key_type:
|
if not primary_key_type:
|
||||||
# no explicit primary key, set pk to Any and add id
|
# no explicit primary key, set pk to Any and add id
|
||||||
primary_key_type = AnyType(TypeOfAny.special_form)
|
primary_key_type = AnyType(TypeOfAny.special_form)
|
||||||
@@ -143,7 +143,7 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
|
|||||||
expected_types[name + '_id'] = AnyType(TypeOfAny.from_unimported_type)
|
expected_types[name + '_id'] = AnyType(TypeOfAny.from_unimported_type)
|
||||||
|
|
||||||
elif isinstance(typ, Instance):
|
elif isinstance(typ, Instance):
|
||||||
field_type = extract_field_setter_type(typ)
|
field_type = helpers.extract_field_setter_type(typ)
|
||||||
if field_type is None:
|
if field_type is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -156,8 +156,9 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
|
|||||||
if is_nullable:
|
if is_nullable:
|
||||||
referred_to_model = helpers.make_required(typ.args[1])
|
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):
|
if isinstance(referred_to_model, Instance) and referred_to_model.type.has_base(
|
||||||
pk_type = extract_explicit_set_type_of_model_primary_key(referred_to_model.type)
|
helpers.MODEL_CLASS_FULLNAME):
|
||||||
|
pk_type = helpers.extract_explicit_set_type_of_model_primary_key(referred_to_model.type)
|
||||||
if not pk_type:
|
if not pk_type:
|
||||||
# extract set type of AutoField
|
# extract set type of AutoField
|
||||||
autofield_info = api.lookup_typeinfo('django.db.models.fields.AutoField')
|
autofield_info = api.lookup_typeinfo('django.db.models.fields.AutoField')
|
||||||
@@ -170,7 +171,7 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
|
|||||||
|
|
||||||
expected_types[name + '_id'] = related_primary_key_type
|
expected_types[name + '_id'] = related_primary_key_type
|
||||||
|
|
||||||
field_metadata = get_fields_metadata(model).get(name, {})
|
field_metadata = helpers.get_fields_metadata(model).get(name, {})
|
||||||
if field_type:
|
if field_type:
|
||||||
# related fields could be None in __init__ (but should be specified before save())
|
# 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,
|
if helpers.has_any_of_bases(typ.type, (helpers.FOREIGN_KEY_FULLNAME,
|
||||||
@@ -178,7 +179,15 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
|
|||||||
field_type = helpers.make_optional(field_type)
|
field_type = helpers.make_optional(field_type)
|
||||||
|
|
||||||
# if primary_key=True and default specified
|
# if primary_key=True and default specified
|
||||||
elif field_metadata.get('primary_key', False) and field_metadata.get('default_specified', False):
|
elif field_metadata.get('primary_key', False) and field_metadata.get('default_specified',
|
||||||
|
False):
|
||||||
|
field_type = helpers.make_optional(field_type)
|
||||||
|
|
||||||
|
# if CharField(blank=True,...) and not nullable, then field can be None in __init__
|
||||||
|
elif (
|
||||||
|
helpers.has_any_of_bases(typ.type, (helpers.CHAR_FIELD_FULLNAME,)) and is_init and
|
||||||
|
field_metadata.get('blank', False) and not field_metadata.get('null', False)
|
||||||
|
):
|
||||||
field_type = helpers.make_optional(field_type)
|
field_type = helpers.make_optional(field_type)
|
||||||
|
|
||||||
expected_types[name] = field_type
|
expected_types[name] = field_type
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from mypy.checker import TypeChecker
|
|||||||
from mypy.nodes import Expression, StrExpr, TypeInfo
|
from mypy.nodes import Expression, StrExpr, TypeInfo
|
||||||
from mypy.plugin import MethodContext
|
from mypy.plugin import MethodContext
|
||||||
from mypy.types import Instance, Type, TypeType
|
from mypy.types import Instance, Type, TypeType
|
||||||
|
|
||||||
from mypy_django_plugin import helpers
|
from mypy_django_plugin import helpers
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,16 @@ from abc import ABCMeta, abstractmethod
|
|||||||
from typing import Dict, Iterator, List, Optional, Tuple, cast
|
from typing import Dict, Iterator, List, Optional, Tuple, cast
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
from mypy.nodes import ARG_STAR, ARG_STAR2, Argument, CallExpr, ClassDef, Expression, IndexExpr, \
|
from mypy.nodes import (
|
||||||
Lvalue, MDEF, MemberExpr, MypyFile, NameExpr, StrExpr, SymbolTableNode, TypeInfo, Var
|
ARG_STAR, ARG_STAR2, MDEF, Argument, CallExpr, ClassDef, Expression, IndexExpr, Lvalue, MemberExpr, MypyFile,
|
||||||
|
NameExpr, StrExpr, SymbolTableNode, TypeInfo, Var,
|
||||||
|
)
|
||||||
from mypy.plugin import ClassDefContext
|
from mypy.plugin import ClassDefContext
|
||||||
from mypy.plugins.common import add_method
|
from mypy.plugins.common import add_method
|
||||||
from mypy.semanal import SemanticAnalyzerPass2
|
from mypy.semanal import SemanticAnalyzerPass2
|
||||||
from mypy.types import AnyType, Instance, NoneTyp, TypeOfAny
|
from mypy.types import AnyType, Instance, NoneTyp, TypeOfAny
|
||||||
|
|
||||||
from mypy_django_plugin import helpers
|
from mypy_django_plugin import helpers
|
||||||
from mypy_django_plugin.helpers import iter_over_assignments
|
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
@@ -40,7 +42,7 @@ class ModelClassInitializer(metaclass=ABCMeta):
|
|||||||
var._fullname = self.model_classdef.info.fullname() + '.' + name
|
var._fullname = self.model_classdef.info.fullname() + '.' + name
|
||||||
var.is_inferred = True
|
var.is_inferred = True
|
||||||
var.is_initialized_in_class = True
|
var.is_initialized_in_class = True
|
||||||
self.model_classdef.info.names[name] = SymbolTableNode(MDEF, var)
|
self.model_classdef.info.names[name] = SymbolTableNode(MDEF, var, plugin_generated=True)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
@@ -48,7 +50,7 @@ class ModelClassInitializer(metaclass=ABCMeta):
|
|||||||
|
|
||||||
|
|
||||||
def iter_call_assignments(klass: ClassDef) -> Iterator[Tuple[Lvalue, CallExpr]]:
|
def iter_call_assignments(klass: ClassDef) -> Iterator[Tuple[Lvalue, CallExpr]]:
|
||||||
for lvalue, rvalue in iter_over_assignments(klass):
|
for lvalue, rvalue in helpers.iter_over_assignments(klass):
|
||||||
if isinstance(rvalue, CallExpr):
|
if isinstance(rvalue, CallExpr):
|
||||||
yield lvalue, rvalue
|
yield lvalue, rvalue
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from typing import Iterable, List, Optional, cast
|
from typing import Iterable, List, Optional, cast
|
||||||
|
|
||||||
from mypy.nodes import ClassDef, Context, ImportAll, MypyFile, SymbolNode, SymbolTableNode, TypeInfo, Var
|
from mypy.nodes import (
|
||||||
|
ClassDef, Context, ImportAll, MypyFile, SymbolNode, SymbolTableNode, TypeInfo, Var,
|
||||||
|
)
|
||||||
from mypy.plugin import ClassDefContext
|
from mypy.plugin import ClassDefContext
|
||||||
from mypy.semanal import SemanticAnalyzerPass2
|
from mypy.semanal import SemanticAnalyzerPass2
|
||||||
from mypy.types import AnyType, Instance, NoneTyp, Type, TypeOfAny, UnionType
|
from mypy.types import AnyType, Instance, NoneTyp, Type, TypeOfAny, UnionType
|
||||||
@@ -56,8 +58,8 @@ def load_settings_from_names(settings_classdef: ClassDef,
|
|||||||
settings_classdef.info.names[name] = copied
|
settings_classdef.info.names[name] = copied
|
||||||
else:
|
else:
|
||||||
var = Var(name, AnyType(TypeOfAny.unannotated))
|
var = Var(name, AnyType(TypeOfAny.unannotated))
|
||||||
var.info = api.named_type('__builtins__.object').type
|
var.info = api.named_type('__builtins__.object').type # outer class type
|
||||||
settings_classdef.info.names[name] = SymbolTableNode(sym.kind, var)
|
settings_classdef.info.names[name] = SymbolTableNode(sym.kind, var, plugin_generated=True)
|
||||||
|
|
||||||
settings_metadata[name] = module.fullname()
|
settings_metadata[name] = module.fullname()
|
||||||
|
|
||||||
@@ -67,11 +69,12 @@ def get_import_star_modules(api: SemanticAnalyzerPass2, module: MypyFile) -> Lis
|
|||||||
for module_import in module.imports:
|
for module_import in module.imports:
|
||||||
# relative import * are not resolved by mypy
|
# relative import * are not resolved by mypy
|
||||||
if isinstance(module_import, ImportAll) and module_import.relative:
|
if isinstance(module_import, ImportAll) and module_import.relative:
|
||||||
absolute_import_path, correct = correct_relative_import(module.fullname(), module_import.relative, module_import.id,
|
absolute_import_path, correct = correct_relative_import(module.fullname(), module_import.relative,
|
||||||
is_cur_package_init_file=False)
|
module_import.id, is_cur_package_init_file=False)
|
||||||
if not correct:
|
if not correct:
|
||||||
return []
|
return []
|
||||||
for path in [absolute_import_path] + get_import_star_modules(api, module=api.modules.get(absolute_import_path)):
|
for path in [absolute_import_path] + get_import_star_modules(api,
|
||||||
|
module=api.modules.get(absolute_import_path)):
|
||||||
if path not in import_star_modules:
|
if path not in import_star_modules:
|
||||||
import_star_modules.append(path)
|
import_star_modules.append(path)
|
||||||
return import_star_modules
|
return import_star_modules
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
[pytest]
|
[pytest]
|
||||||
|
|
||||||
testpaths = ./test-data
|
testpaths = ./test-data
|
||||||
addopts =
|
addopts =
|
||||||
--tb=native
|
--tb=native
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import itertools
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
@@ -37,7 +38,8 @@ IGNORED_ERRORS = {
|
|||||||
# settings
|
# settings
|
||||||
re.compile(r'Module has no attribute "[A-Z_]+"'),
|
re.compile(r'Module has no attribute "[A-Z_]+"'),
|
||||||
# attributes assigned to test functions
|
# attributes assigned to test functions
|
||||||
re.compile(r'"Callable\[(\[(Any(, )?)*((, )?VarArg\(Any\))?((, )?KwArg\(Any\))?\]|\.\.\.), Any\]" has no attribute'),
|
re.compile(
|
||||||
|
r'"Callable\[(\[(Any(, )?)*((, )?VarArg\(Any\))?((, )?KwArg\(Any\))?\]|\.\.\.), Any\]" has no attribute'),
|
||||||
# assign empty tuple
|
# assign empty tuple
|
||||||
re.compile(r'Incompatible types in assignment \(expression has type "Tuple\[\]", '
|
re.compile(r'Incompatible types in assignment \(expression has type "Tuple\[\]", '
|
||||||
r'variable has type "Tuple\[[A-Za-z, ]+\]"'),
|
r'variable has type "Tuple\[[A-Za-z, ]+\]"'),
|
||||||
@@ -54,8 +56,10 @@ IGNORED_ERRORS = {
|
|||||||
'ValuesIterable',
|
'ValuesIterable',
|
||||||
'Value of type "Optional[Dict[str, Any]]" is not indexable',
|
'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 "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]"',
|
'Argument 1 to "loads" has incompatible type "Union[bytes, str, None]"; '
|
||||||
'Incompatible types in assignment (expression has type "None", variable has type Module)'
|
+ 'expected "Union[str, bytes, bytearray]"',
|
||||||
|
'Incompatible types in assignment (expression has type "None", variable has type Module)',
|
||||||
|
'note:'
|
||||||
],
|
],
|
||||||
'admin_changelist': [
|
'admin_changelist': [
|
||||||
'Incompatible types in assignment (expression has type "FilteredChildAdmin", variable has type "ChildAdmin")'
|
'Incompatible types in assignment (expression has type "FilteredChildAdmin", variable has type "ChildAdmin")'
|
||||||
@@ -65,8 +69,9 @@ IGNORED_ERRORS = {
|
|||||||
],
|
],
|
||||||
'admin_widgets': [
|
'admin_widgets': [
|
||||||
'Incompatible types in assignment (expression has type "RelatedFieldWidgetWrapper", '
|
'Incompatible types in assignment (expression has type "RelatedFieldWidgetWrapper", '
|
||||||
'variable has type "AdminRadioSelect")',
|
+ 'variable has type "AdminRadioSelect")',
|
||||||
'Incompatible types in assignment (expression has type "Union[Widget, Any]", variable has type "AutocompleteSelect")'
|
'Incompatible types in assignment (expression has type "Union[Widget, Any]", '
|
||||||
|
+ 'variable has type "AutocompleteSelect")'
|
||||||
],
|
],
|
||||||
'admin_utils': [
|
'admin_utils': [
|
||||||
re.compile(r'Argument [0-9] to "lookup_field" has incompatible type'),
|
re.compile(r'Argument [0-9] to "lookup_field" has incompatible type'),
|
||||||
@@ -86,17 +91,10 @@ IGNORED_ERRORS = {
|
|||||||
'Argument "is_dst" to "localize" of "BaseTzInfo" has incompatible type "None"; expected "bool"'
|
'Argument "is_dst" to "localize" of "BaseTzInfo" has incompatible type "None"; expected "bool"'
|
||||||
],
|
],
|
||||||
'aggregation': [
|
'aggregation': [
|
||||||
'Incompatible types in assignment (expression has type "QuerySet[Any]", variable has type "List[Any]")',
|
|
||||||
'"as_sql" undefined in superclass',
|
'"as_sql" undefined in superclass',
|
||||||
'Incompatible types in assignment (expression has type "FlatValuesListIterable", '
|
|
||||||
+ 'variable has type "ValuesListIterable")',
|
|
||||||
'Incompatible type for "contact" of "Book" (got "Optional[Author]", expected "Union[Author, Combinable]")',
|
'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]")'
|
'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]")',
|
|
||||||
'Incompatible types in assignment (expression has type "FlatValuesListIterable", variable has type "QuerySet[Any]")',
|
|
||||||
'Too few arguments for "count" of "Sequence"'
|
|
||||||
],
|
],
|
||||||
'apps': [
|
'apps': [
|
||||||
'Incompatible types in assignment (expression has type "str", target has type "type")',
|
'Incompatible types in assignment (expression has type "str", target has type "type")',
|
||||||
@@ -152,9 +150,6 @@ IGNORED_ERRORS = {
|
|||||||
'db_typecasts': [
|
'db_typecasts': [
|
||||||
'"object" has no attribute "__iter__"; maybe "__str__" or "__dir__"? (not iterable)'
|
'"object" has no attribute "__iter__"; maybe "__str__" or "__dir__"? (not iterable)'
|
||||||
],
|
],
|
||||||
'expressions': [
|
|
||||||
'Argument 1 to "Subquery" has incompatible type "Sequence[Dict[str, Any]]"; expected "QuerySet[Any]"'
|
|
||||||
],
|
|
||||||
'from_db_value': [
|
'from_db_value': [
|
||||||
'has no attribute "vendor"'
|
'has no attribute "vendor"'
|
||||||
],
|
],
|
||||||
@@ -176,8 +171,8 @@ IGNORED_ERRORS = {
|
|||||||
'variable has type "SongForm"',
|
'variable has type "SongForm"',
|
||||||
'"full_clean" of "BaseForm" does not return a value',
|
'"full_clean" of "BaseForm" does not return a value',
|
||||||
'No overload variant of "zip" matches argument types "Tuple[str, str, str]", "object"',
|
'No overload variant of "zip" matches argument types "Tuple[str, str, str]", "object"',
|
||||||
'note:',
|
'Incompatible types in assignment (expression has type "GetDateShowHiddenInitial", '
|
||||||
'Incompatible types in assignment (expression has type "GetDateShowHiddenInitial", variable has type "GetDate")',
|
+ 'variable has type "GetDate")',
|
||||||
re.compile(r'Incompatible types in assignment \(expression has type "[a-zA-Z]+Field", '
|
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\]"\)'),
|
r'base class "BaseForm" defined the type as "Dict\[str, Any\]"\)'),
|
||||||
'List or tuple expected as variable arguments',
|
'List or tuple expected as variable arguments',
|
||||||
@@ -188,13 +183,13 @@ IGNORED_ERRORS = {
|
|||||||
'Incompatible types in assignment (expression has type "TestForm", variable has type "Person")',
|
'Incompatible types in assignment (expression has type "TestForm", variable has type "Person")',
|
||||||
'Incompatible types in assignment (expression has type "Type[Textarea]", '
|
'Incompatible types in assignment (expression has type "Type[Textarea]", '
|
||||||
+ 'base class "Field" defined the type as "Widget")',
|
+ 'base class "Field" defined the type as "Widget")',
|
||||||
'Incompatible types in assignment (expression has type "SimpleUploadedFile", variable has type "BinaryIO")'
|
'Incompatible types in assignment (expression has type "SimpleUploadedFile", variable has type "BinaryIO")',
|
||||||
],
|
],
|
||||||
'get_object_or_404': [
|
'get_object_or_404': [
|
||||||
'Argument 1 to "get_object_or_404" has incompatible type "str"; '
|
'Argument 1 to "get_object_or_404" has incompatible type "str"; '
|
||||||
+ 'expected "Union[Type[<nothing>], Manager[<nothing>], QuerySet[<nothing>]]"',
|
+ 'expected "Union[Type[<nothing>], QuerySet[<nothing>, <nothing>]]"',
|
||||||
'Argument 1 to "get_list_or_404" has incompatible type "List[Type[Article]]"; '
|
'Argument 1 to "get_list_or_404" has incompatible type "List[Type[Article]]"; '
|
||||||
+ 'expected "Union[Type[<nothing>], Manager[<nothing>], QuerySet[<nothing>]]"',
|
+ 'expected "Union[Type[<nothing>], QuerySet[<nothing>, <nothing>]]"',
|
||||||
'CustomClass'
|
'CustomClass'
|
||||||
],
|
],
|
||||||
'get_or_create': [
|
'get_or_create': [
|
||||||
@@ -216,14 +211,10 @@ IGNORED_ERRORS = {
|
|||||||
],
|
],
|
||||||
'lookup': [
|
'lookup': [
|
||||||
'Unexpected keyword argument "headline__startswith" for "in_bulk" of "QuerySet"',
|
'Unexpected keyword argument "headline__startswith" for "in_bulk" of "QuerySet"',
|
||||||
'note: '
|
|
||||||
],
|
],
|
||||||
'many_to_one': [
|
'many_to_one': [
|
||||||
'Incompatible type for "parent" of "Child" (got "None", expected "Union[Parent, Combinable]")'
|
'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]")'
|
|
||||||
],
|
|
||||||
'model_meta': [
|
'model_meta': [
|
||||||
'"object" has no attribute "items"',
|
'"object" has no attribute "items"',
|
||||||
'"Field" has no attribute "many_to_many"'
|
'"Field" has no attribute "many_to_many"'
|
||||||
@@ -238,10 +229,10 @@ IGNORED_ERRORS = {
|
|||||||
'Cannot assign multiple types to name "PersonTwoImages" without an explicit "Type[...]" annotation',
|
'Cannot assign multiple types to name "PersonTwoImages" without an explicit "Type[...]" annotation',
|
||||||
'Incompatible types in assignment (expression has type "Type[Person]", '
|
'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': [
|
'model_formsets': [
|
||||||
'Incompatible types in string interpolation (expression has type "object", placeholder has type "Union[int, float]")'
|
'Incompatible types in string interpolation (expression has type "object", '
|
||||||
|
+ 'placeholder has type "Union[int, float]")'
|
||||||
],
|
],
|
||||||
'model_formsets_regress': [
|
'model_formsets_regress': [
|
||||||
'Incompatible types in assignment (expression has type "Model", variable has type "User")'
|
'Incompatible types in assignment (expression has type "Model", variable has type "User")'
|
||||||
@@ -287,16 +278,19 @@ IGNORED_ERRORS = {
|
|||||||
'Incompatible types in assignment (expression has type "Type[Field[Any, Any]]',
|
'Incompatible types in assignment (expression has type "Type[Field[Any, Any]]',
|
||||||
'DummyArrayField',
|
'DummyArrayField',
|
||||||
'DummyJSONField',
|
'DummyJSONField',
|
||||||
'Argument "encoder" to "JSONField" has incompatible type "DjangoJSONEncoder"; expected "Optional[Type[JSONEncoder]]"',
|
'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]")'
|
'Incompatible type for "field" of "IntegerArrayModel" (got "None", '
|
||||||
|
+ 'expected "Union[Sequence[int], Combinable]")'
|
||||||
],
|
],
|
||||||
'properties': [
|
'properties': [
|
||||||
re.compile('Unexpected attribute "(full_name|full_name_2)" for model "Person"')
|
re.compile('Unexpected attribute "(full_name|full_name_2)" for model "Person"')
|
||||||
],
|
],
|
||||||
'queries': [
|
'queries': [
|
||||||
'Incompatible types in assignment (expression has type "None", variable has type "str")',
|
'Incompatible types in assignment (expression has type "None", variable has type "str")',
|
||||||
'Invalid index type "Optional[str]" for "Dict[str, int]"; expected type "str"'
|
'Invalid index type "Optional[str]" for "Dict[str, int]"; expected type "str"',
|
||||||
|
'No overload variant of "values_list" of "QuerySet" matches argument types "str", "bool", "bool"',
|
||||||
],
|
],
|
||||||
'requests': [
|
'requests': [
|
||||||
'Incompatible types in assignment (expression has type "Dict[str, str]", variable has type "QueryDict")'
|
'Incompatible types in assignment (expression has type "Dict[str, str]", variable has type "QueryDict")'
|
||||||
@@ -305,7 +299,7 @@ IGNORED_ERRORS = {
|
|||||||
'Argument 1 to "TextIOWrapper" has incompatible type "HttpResponse"; expected "IO[bytes]"'
|
'Argument 1 to "TextIOWrapper" has incompatible type "HttpResponse"; expected "IO[bytes]"'
|
||||||
],
|
],
|
||||||
'prefetch_related': [
|
'prefetch_related': [
|
||||||
'Incompatible types in assignment (expression has type "List[Room]", variable has type "QuerySet[Room]")',
|
'Incompatible types in assignment (expression has type "List[Room]", variable has type "QuerySet[Room, Room]")',
|
||||||
'"None" has no attribute "__iter__"',
|
'"None" has no attribute "__iter__"',
|
||||||
'has no attribute "read_by"'
|
'has no attribute "read_by"'
|
||||||
],
|
],
|
||||||
@@ -334,11 +328,14 @@ IGNORED_ERRORS = {
|
|||||||
'Incompatible types in assignment (expression has type "Thread", variable has type "Callable[[], Any]")'
|
'Incompatible types in assignment (expression has type "Thread", variable has type "Callable[[], Any]")'
|
||||||
],
|
],
|
||||||
'test_client': [
|
'test_client': [
|
||||||
'Incompatible types in assignment (expression has type "StreamingHttpResponse", variable has type "HttpResponse")',
|
'Incompatible types in assignment (expression has type "StreamingHttpResponse", '
|
||||||
'Incompatible types in assignment (expression has type "HttpResponse", variable has type "StreamingHttpResponse")'
|
+ 'variable has type "HttpResponse")',
|
||||||
|
'Incompatible types in assignment (expression has type "HttpResponse", '
|
||||||
|
+ 'variable has type "StreamingHttpResponse")'
|
||||||
],
|
],
|
||||||
'test_client_regress': [
|
'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")',
|
'Unsupported left operand type for + ("None")',
|
||||||
'Both left and right operands are unions'
|
'Both left and right operands are unions'
|
||||||
],
|
],
|
||||||
@@ -348,7 +345,8 @@ IGNORED_ERRORS = {
|
|||||||
'test_runner': [
|
'test_runner': [
|
||||||
'Value of type "TestSuite" is not indexable',
|
'Value of type "TestSuite" is not indexable',
|
||||||
'"TestSuite" has no attribute "_tests"',
|
'"TestSuite" has no attribute "_tests"',
|
||||||
'Argument "result" to "run" of "TestCase" has incompatible type "RemoteTestResult"; expected "Optional[TestResult]"',
|
'Argument "result" to "run" of "TestCase" has incompatible type "RemoteTestResult"; '
|
||||||
|
+ 'expected "Optional[TestResult]"',
|
||||||
'Item "TestSuite" of "Union[TestCase, TestSuite]" has no attribute "id"',
|
'Item "TestSuite" of "Union[TestCase, TestSuite]" has no attribute "id"',
|
||||||
'MockTestRunner',
|
'MockTestRunner',
|
||||||
'Incompatible types in assignment (expression has type "Tuple[Union[TestCase, TestSuite], ...]", '
|
'Incompatible types in assignment (expression has type "Tuple[Union[TestCase, TestSuite], ...]", '
|
||||||
@@ -631,7 +629,8 @@ def cd(path):
|
|||||||
|
|
||||||
|
|
||||||
def is_ignored(line: str, test_folder_name: str) -> bool:
|
def is_ignored(line: str, test_folder_name: str) -> bool:
|
||||||
for pattern in IGNORED_ERRORS['__common__'] + IGNORED_ERRORS.get(test_folder_name, []):
|
for pattern in itertools.chain(IGNORED_ERRORS['__common__'],
|
||||||
|
IGNORED_ERRORS.get(test_folder_name, [])):
|
||||||
if isinstance(pattern, Pattern):
|
if isinstance(pattern, Pattern):
|
||||||
if pattern.search(line):
|
if pattern.search(line):
|
||||||
return True
|
return True
|
||||||
|
|||||||
29
setup.cfg
Normal file
29
setup.cfg
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
[isort]
|
||||||
|
skip =
|
||||||
|
django-sources,
|
||||||
|
django-stubs,
|
||||||
|
test-data
|
||||||
|
include_trailing_comma = true
|
||||||
|
multi_line_output = 5
|
||||||
|
wrap_length = 120
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
exclude =
|
||||||
|
django-sources,
|
||||||
|
django-stubs,
|
||||||
|
test-data
|
||||||
|
max_line_length = 120
|
||||||
|
|
||||||
|
[tool:pytest]
|
||||||
|
testpaths = ./test-data
|
||||||
|
addopts =
|
||||||
|
--tb=native
|
||||||
|
--mypy-ini-file=./test-data/plugins.ini
|
||||||
|
-s
|
||||||
|
-v
|
||||||
|
|
||||||
|
[bdist_wheel]
|
||||||
|
universal = 1
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
license_file = LICENSE.txt
|
||||||
3
setup.py
3
setup.py
@@ -21,7 +21,6 @@ with open('README.md', 'r') as f:
|
|||||||
readme = f.read()
|
readme = f.read()
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
'Django',
|
|
||||||
'mypy>=0.670',
|
'mypy>=0.670',
|
||||||
'typing-extensions'
|
'typing-extensions'
|
||||||
]
|
]
|
||||||
@@ -31,7 +30,7 @@ if sys.version_info[:2] < (3, 7):
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="django-stubs",
|
name="django-stubs",
|
||||||
version="0.8.0",
|
version="0.9.0",
|
||||||
description='Django mypy stubs',
|
description='Django mypy stubs',
|
||||||
long_description=readme,
|
long_description=readme,
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
|
|||||||
@@ -110,9 +110,22 @@ class MyModel(ParentModel):
|
|||||||
reveal_type(MyModel().id) # E: Revealed type is 'uuid.UUID*'
|
reveal_type(MyModel().id) # E: Revealed type is 'uuid.UUID*'
|
||||||
[/CASE]
|
[/CASE]
|
||||||
|
|
||||||
[CASE blank_for_charfield_is_the_same_as_null]
|
[CASE blank_and_null_char_field_allows_none]
|
||||||
from django.db import models
|
from django.db import models
|
||||||
class MyModel(models.Model):
|
class MyModel(models.Model):
|
||||||
text = models.CharField(max_length=30, blank=True)
|
nulltext=models.CharField(max_length=1, blank=True, null=True)
|
||||||
MyModel(text=None)
|
MyModel(nulltext="")
|
||||||
|
MyModel(nulltext=None)
|
||||||
|
MyModel().nulltext=None
|
||||||
|
reveal_type(MyModel().nulltext) # E: Revealed type is 'Union[builtins.str, None]'
|
||||||
|
[/CASE]
|
||||||
|
|
||||||
|
[CASE blank_and_not_null_charfield_does_not_allow_none]
|
||||||
|
from django.db import models
|
||||||
|
class MyModel(models.Model):
|
||||||
|
notnulltext=models.CharField(max_length=1, blank=True, null=False)
|
||||||
|
MyModel(notnulltext=None) # Should allow None in constructor
|
||||||
|
MyModel(notnulltext="")
|
||||||
|
MyModel().notnulltext = None # E: Incompatible types in assignment (expression has type "None", variable has type "Union[str, int, Combinable]")
|
||||||
|
reveal_type(MyModel().notnulltext) # E: Revealed type is 'builtins.str*'
|
||||||
[/CASE]
|
[/CASE]
|
||||||
|
|||||||
@@ -137,3 +137,65 @@ class AbstractBase2(models.Model):
|
|||||||
class Child(AbstractBase1, AbstractBase2):
|
class Child(AbstractBase1, AbstractBase2):
|
||||||
pass
|
pass
|
||||||
[out]
|
[out]
|
||||||
|
|
||||||
|
[CASE managers_from_unrelated_models_dont_interfere]
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Normal scenario where one model has a manager with an annotation of the same type as the model
|
||||||
|
class UnrelatedModel(models.Model):
|
||||||
|
objects = models.Manager[UnrelatedModel]()
|
||||||
|
|
||||||
|
class MyModel(models.Model):
|
||||||
|
pass
|
||||||
|
|
||||||
|
reveal_type(UnrelatedModel.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.UnrelatedModel]'
|
||||||
|
reveal_type(UnrelatedModel.objects.first()) # E: Revealed type is 'Union[main.UnrelatedModel*, None]'
|
||||||
|
|
||||||
|
reveal_type(MyModel.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel]'
|
||||||
|
reveal_type(MyModel.objects.first()) # E: Revealed type is 'Union[main.MyModel*, None]'
|
||||||
|
|
||||||
|
# Possible to specify objects without explicit annotation of models.Manager()
|
||||||
|
class UnrelatedModel2(models.Model):
|
||||||
|
objects = models.Manager()
|
||||||
|
|
||||||
|
class MyModel2(models.Model):
|
||||||
|
pass
|
||||||
|
|
||||||
|
reveal_type(UnrelatedModel2.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.UnrelatedModel2]'
|
||||||
|
reveal_type(UnrelatedModel2.objects.first()) # E: Revealed type is 'Union[main.UnrelatedModel2*, None]'
|
||||||
|
|
||||||
|
reveal_type(MyModel2.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel2]'
|
||||||
|
reveal_type(MyModel2.objects.first()) # E: Revealed type is 'Union[main.MyModel2*, None]'
|
||||||
|
|
||||||
|
|
||||||
|
# Inheritance works
|
||||||
|
class ParentOfMyModel3(models.Model):
|
||||||
|
objects = models.Manager()
|
||||||
|
|
||||||
|
class MyModel3(ParentOfMyModel3):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
reveal_type(ParentOfMyModel3.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.ParentOfMyModel3]'
|
||||||
|
reveal_type(ParentOfMyModel3.objects.first()) # E: Revealed type is 'Union[main.ParentOfMyModel3*, None]'
|
||||||
|
|
||||||
|
reveal_type(MyModel3.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel3]'
|
||||||
|
reveal_type(MyModel3.objects.first()) # E: Revealed type is 'Union[main.MyModel3*, None]'
|
||||||
|
|
||||||
|
|
||||||
|
# Inheritance works with explicit objects in child
|
||||||
|
class ParentOfMyModel4(models.Model):
|
||||||
|
objects = models.Manager()
|
||||||
|
|
||||||
|
class MyModel4(ParentOfMyModel4):
|
||||||
|
objects = models.Manager[MyModel4]()
|
||||||
|
|
||||||
|
reveal_type(ParentOfMyModel4.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.ParentOfMyModel4]'
|
||||||
|
reveal_type(ParentOfMyModel4.objects.first()) # E: Revealed type is 'Union[main.ParentOfMyModel4*, None]'
|
||||||
|
|
||||||
|
reveal_type(MyModel4.objects) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel4]'
|
||||||
|
reveal_type(MyModel4.objects.first()) # E: Revealed type is 'Union[main.MyModel4*, None]'
|
||||||
|
|
||||||
|
|
||||||
|
[out]
|
||||||
@@ -2,9 +2,94 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
class Blog(models.Model):
|
class Blog(models.Model):
|
||||||
slug = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
|
created_at = models.DateTimeField()
|
||||||
|
|
||||||
|
# QuerySet where second type argument is not specified shouldn't raise any errors
|
||||||
|
class BlogQuerySet(models.QuerySet[Blog]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Test that second type argument gets filled automatically
|
||||||
|
blog_qs: models.QuerySet[Blog]
|
||||||
|
reveal_type(blog_qs) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog, main.Blog]'
|
||||||
|
|
||||||
|
|
||||||
reveal_type(Blog.objects.in_bulk([1])) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
reveal_type(Blog.objects.in_bulk([1])) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
||||||
reveal_type(Blog.objects.in_bulk()) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
reveal_type(Blog.objects.in_bulk()) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
||||||
reveal_type(Blog.objects.in_bulk(['beatles_blog'], field_name='slug')) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
reveal_type(Blog.objects.in_bulk(['beatles_blog'], field_name='name')) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
||||||
|
|
||||||
|
# When ANDing QuerySets, the left-side's _Row parameter is used
|
||||||
|
reveal_type(Blog.objects.all() & Blog.objects.values()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, main.Blog*]'
|
||||||
|
reveal_type(Blog.objects.values() & Blog.objects.values()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.dict*[builtins.str, Any]]'
|
||||||
|
reveal_type(Blog.objects.values_list('id', 'name') & Blog.objects.values()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.tuple*[Any]]'
|
||||||
|
reveal_type(Blog.objects.values_list('id', 'name', named=True) & Blog.objects.values()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, typing.NamedTuple*]'
|
||||||
|
reveal_type(Blog.objects.values_list('id', flat=True) & Blog.objects.values()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, Any]'
|
||||||
|
|
||||||
|
# .dates / .datetimes
|
||||||
|
reveal_type(Blog.objects.dates("created_at", "day")) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, datetime.date]'
|
||||||
|
reveal_type(Blog.objects.datetimes("created_at", "day")) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, datetime.datetime]'
|
||||||
|
|
||||||
|
qs = Blog.objects.all()
|
||||||
|
reveal_type(qs) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, main.Blog*]'
|
||||||
|
reveal_type(qs.get(id=1)) # E: Revealed type is 'main.Blog*'
|
||||||
|
reveal_type(iter(qs)) # E: Revealed type is 'typing.Iterator[main.Blog*]'
|
||||||
|
reveal_type(qs.iterator()) # E: Revealed type is 'typing.Iterator[main.Blog*]'
|
||||||
|
reveal_type(qs.first()) # E: Revealed type is 'Union[main.Blog*, None]'
|
||||||
|
reveal_type(qs.earliest()) # E: Revealed type is 'main.Blog*'
|
||||||
|
reveal_type(qs[0]) # E: Revealed type is 'main.Blog*'
|
||||||
|
reveal_type(qs[:9]) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, main.Blog*]'
|
||||||
|
reveal_type(qs.in_bulk()) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
||||||
|
|
||||||
|
|
||||||
|
values_qs = Blog.objects.values()
|
||||||
|
reveal_type(values_qs) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.dict[builtins.str, Any]]'
|
||||||
|
reveal_type(values_qs.all()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.dict*[builtins.str, Any]]'
|
||||||
|
reveal_type(values_qs.get(id=1)) # E: Revealed type is 'builtins.dict*[builtins.str, Any]'
|
||||||
|
reveal_type(iter(values_qs)) # E: Revealed type is 'typing.Iterator[builtins.dict*[builtins.str, Any]]'
|
||||||
|
reveal_type(values_qs.iterator()) # E: Revealed type is 'typing.Iterator[builtins.dict*[builtins.str, Any]]'
|
||||||
|
reveal_type(values_qs.first()) # E: Revealed type is 'Union[builtins.dict*[builtins.str, Any], None]'
|
||||||
|
reveal_type(values_qs.earliest()) # E: Revealed type is 'builtins.dict*[builtins.str, Any]'
|
||||||
|
reveal_type(values_qs[0]) # E: Revealed type is 'builtins.dict*[builtins.str, Any]'
|
||||||
|
reveal_type(values_qs[:9]) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.dict*[builtins.str, Any]]'
|
||||||
|
reveal_type(values_qs.in_bulk()) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
||||||
|
|
||||||
|
|
||||||
|
values_list_qs = Blog.objects.values_list('id', 'name')
|
||||||
|
reveal_type(values_list_qs) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.tuple[Any]]'
|
||||||
|
reveal_type(values_list_qs.all()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.tuple*[Any]]'
|
||||||
|
reveal_type(values_list_qs.get(id=1)) # E: Revealed type is 'builtins.tuple*[Any]'
|
||||||
|
reveal_type(iter(values_list_qs)) # E: Revealed type is 'typing.Iterator[builtins.tuple*[Any]]'
|
||||||
|
reveal_type(values_list_qs.iterator()) # E: Revealed type is 'typing.Iterator[builtins.tuple*[Any]]'
|
||||||
|
reveal_type(values_list_qs.first()) # E: Revealed type is 'Union[builtins.tuple*[Any], None]'
|
||||||
|
reveal_type(values_list_qs.earliest()) # E: Revealed type is 'builtins.tuple*[Any]'
|
||||||
|
reveal_type(values_list_qs[0]) # E: Revealed type is 'builtins.tuple*[Any]'
|
||||||
|
reveal_type(values_list_qs[:9]) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.tuple*[Any]]'
|
||||||
|
reveal_type(values_list_qs.in_bulk()) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
||||||
|
|
||||||
|
|
||||||
|
flat_values_list_qs = Blog.objects.values_list('id', flat=True)
|
||||||
|
reveal_type(flat_values_list_qs) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, Any]'
|
||||||
|
reveal_type(flat_values_list_qs.all()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, Any]'
|
||||||
|
reveal_type(flat_values_list_qs.get(id=1)) # E: Revealed type is 'Any'
|
||||||
|
reveal_type(iter(flat_values_list_qs)) # E: Revealed type is 'typing.Iterator[Any]'
|
||||||
|
reveal_type(flat_values_list_qs.iterator()) # E: Revealed type is 'typing.Iterator[Any]'
|
||||||
|
reveal_type(flat_values_list_qs.first()) # E: Revealed type is 'Union[Any, None]'
|
||||||
|
reveal_type(flat_values_list_qs.earliest()) # E: Revealed type is 'Any'
|
||||||
|
reveal_type(flat_values_list_qs[0]) # E: Revealed type is 'Any'
|
||||||
|
reveal_type(flat_values_list_qs[:9]) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, Any]'
|
||||||
|
reveal_type(flat_values_list_qs.in_bulk()) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
||||||
|
|
||||||
|
|
||||||
|
named_values_list_qs = Blog.objects.values_list('id', named=True)
|
||||||
|
reveal_type(named_values_list_qs) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, typing.NamedTuple]'
|
||||||
|
reveal_type(named_values_list_qs.all()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, typing.NamedTuple*]'
|
||||||
|
reveal_type(named_values_list_qs.get(id=1)) # E: Revealed type is 'typing.NamedTuple*'
|
||||||
|
reveal_type(iter(named_values_list_qs)) # E: Revealed type is 'typing.Iterator[typing.NamedTuple*]'
|
||||||
|
reveal_type(named_values_list_qs.iterator()) # E: Revealed type is 'typing.Iterator[typing.NamedTuple*]'
|
||||||
|
reveal_type(named_values_list_qs.first()) # E: Revealed type is 'Union[typing.NamedTuple*, None]'
|
||||||
|
reveal_type(named_values_list_qs.earliest()) # E: Revealed type is 'typing.NamedTuple*'
|
||||||
|
reveal_type(named_values_list_qs[0]) # E: Revealed type is 'typing.NamedTuple*'
|
||||||
|
reveal_type(named_values_list_qs[:9]) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, typing.NamedTuple*]'
|
||||||
|
reveal_type(named_values_list_qs.in_bulk()) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
|
||||||
|
|
||||||
[out]
|
[out]
|
||||||
|
|||||||
Reference in New Issue
Block a user