mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-11 22:41:55 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
304cb19de6 | ||
|
|
c57f4f7152 | ||
|
|
8a826fee1e | ||
|
|
37d85c2ca6 | ||
|
|
71fb0432f3 | ||
|
|
9288c34648 | ||
|
|
70050f28b9 | ||
|
|
4338c17970 | ||
|
|
91f789c38c |
@@ -1,8 +1,6 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Dict, Optional, Union
|
from typing import Any, Dict, Optional, Union
|
||||||
|
|
||||||
from django.db.models.base import Model
|
|
||||||
|
|
||||||
VALID_KEY_CHARS: Any
|
VALID_KEY_CHARS: Any
|
||||||
|
|
||||||
class CreateError(Exception): ...
|
class CreateError(Exception): ...
|
||||||
@@ -18,8 +16,8 @@ class SessionBase(Dict[str, Any]):
|
|||||||
def set_test_cookie(self) -> None: ...
|
def set_test_cookie(self) -> None: ...
|
||||||
def test_cookie_worked(self) -> bool: ...
|
def test_cookie_worked(self) -> bool: ...
|
||||||
def delete_test_cookie(self) -> None: ...
|
def delete_test_cookie(self) -> None: ...
|
||||||
def encode(self, session_dict: Dict[str, Model]) -> str: ...
|
def encode(self, session_dict: Dict[str, Any]) -> str: ...
|
||||||
def decode(self, session_data: Union[bytes, str]) -> Dict[str, Model]: ...
|
def decode(self, session_data: Union[bytes, str]) -> Dict[str, Any]: ...
|
||||||
def has_key(self, key: Any): ...
|
def has_key(self, key: Any): ...
|
||||||
def keys(self): ...
|
def keys(self): ...
|
||||||
def values(self): ...
|
def values(self): ...
|
||||||
@@ -33,7 +31,7 @@ class SessionBase(Dict[str, Any]):
|
|||||||
def get_expire_at_browser_close(self) -> bool: ...
|
def get_expire_at_browser_close(self) -> bool: ...
|
||||||
def flush(self) -> None: ...
|
def flush(self) -> None: ...
|
||||||
def cycle_key(self) -> None: ...
|
def cycle_key(self) -> None: ...
|
||||||
def exists(self, session_key: str) -> None: ...
|
def exists(self, session_key: str) -> bool: ...
|
||||||
def create(self) -> None: ...
|
def create(self) -> None: ...
|
||||||
def save(self, must_create: bool = ...) -> None: ...
|
def save(self, must_create: bool = ...) -> None: ...
|
||||||
def delete(self, session_key: Optional[Any] = ...) -> None: ...
|
def delete(self, session_key: Optional[Any] = ...) -> None: ...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from collections import OrderedDict
|
from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple, Type, Union, Iterable
|
||||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple, Type, Union
|
|
||||||
|
|
||||||
from django.apps.config import AppConfig
|
from django.apps.config import AppConfig
|
||||||
from django.db.models.base import Model
|
from django.db.models.base import Model
|
||||||
@@ -33,5 +32,5 @@ def serialize(
|
|||||||
) -> Optional[Union[bytes, str]]: ...
|
) -> Optional[Union[bytes, str]]: ...
|
||||||
def deserialize(format: str, stream_or_string: Any, **options: Any) -> Union[Iterator[Any], Deserializer]: ...
|
def deserialize(format: str, stream_or_string: Any, **options: Any) -> Union[Iterator[Any], Deserializer]: ...
|
||||||
def sort_dependencies(
|
def sort_dependencies(
|
||||||
app_list: Union[List[Tuple[AppConfig, None]], List[Tuple[str, List[Type[Model]]]]]
|
app_list: Union[Iterable[Tuple[AppConfig, None]], Iterable[Tuple[str, Iterable[Type[Model]]]]]
|
||||||
) -> List[Type[Model]]: ...
|
) -> List[Type[Model]]: ...
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ _Self = TypeVar("_Self", bound="Model")
|
|||||||
|
|
||||||
class Model(metaclass=ModelBase):
|
class Model(metaclass=ModelBase):
|
||||||
class DoesNotExist(Exception): ...
|
class DoesNotExist(Exception): ...
|
||||||
|
class MultipleObjectsReturned(Exception): ...
|
||||||
class Meta: ...
|
class Meta: ...
|
||||||
_meta: Any
|
_meta: Any
|
||||||
_default_manager: Manager[Model]
|
_default_manager: Manager[Model]
|
||||||
@@ -15,6 +16,7 @@ class Model(metaclass=ModelBase):
|
|||||||
def __init__(self: _Self, *args, **kwargs) -> None: ...
|
def __init__(self: _Self, *args, **kwargs) -> None: ...
|
||||||
def delete(self, using: Any = ..., keep_parents: bool = ...) -> Tuple[int, Dict[str, int]]: ...
|
def delete(self, using: Any = ..., keep_parents: bool = ...) -> Tuple[int, Dict[str, int]]: ...
|
||||||
def full_clean(self, exclude: Optional[List[str]] = ..., validate_unique: bool = ...) -> None: ...
|
def full_clean(self, exclude: Optional[List[str]] = ..., validate_unique: bool = ...) -> None: ...
|
||||||
|
def clean(self) -> None: ...
|
||||||
def clean_fields(self, exclude: List[str] = ...) -> None: ...
|
def clean_fields(self, exclude: List[str] = ...) -> None: ...
|
||||||
def validate_unique(self, exclude: List[str] = ...) -> None: ...
|
def validate_unique(self, exclude: List[str] = ...) -> None: ...
|
||||||
def save(
|
def save(
|
||||||
@@ -34,6 +36,7 @@ class Model(metaclass=ModelBase):
|
|||||||
): ...
|
): ...
|
||||||
def refresh_from_db(self: _Self, using: Optional[str] = ..., fields: Optional[List[str]] = ...) -> _Self: ...
|
def refresh_from_db(self: _Self, using: Optional[str] = ..., fields: Optional[List[str]] = ...) -> _Self: ...
|
||||||
def get_deferred_fields(self) -> Set[str]: ...
|
def get_deferred_fields(self) -> Set[str]: ...
|
||||||
|
def __getstate__(self) -> dict: ...
|
||||||
|
|
||||||
class ModelStateFieldsCacheDescriptor: ...
|
class ModelStateFieldsCacheDescriptor: ...
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
from typing import Any, Callable, Optional, Set, Tuple, Type, Union
|
from typing import Any, Callable, Optional, Set, Tuple, Type, Union
|
||||||
|
|
||||||
from django.middleware.cache import CacheMiddleware
|
|
||||||
from django.test.testcases import LiveServerTestCase
|
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
|
|
||||||
class classonlymethod(classmethod): ...
|
class classonlymethod(classmethod): ...
|
||||||
@@ -9,7 +7,7 @@ class classonlymethod(classmethod): ...
|
|||||||
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 = ...
|
||||||
) -> Callable: ...
|
) -> Callable: ...
|
||||||
def decorator_from_middleware_with_args(middleware_class: Type[CacheMiddleware]) -> Callable: ...
|
def decorator_from_middleware_with_args(middleware_class: Type[MiddlewareMixin]) -> Callable: ...
|
||||||
def decorator_from_middleware(middleware_class: Type[MiddlewareMixin]) -> Callable: ...
|
def decorator_from_middleware(middleware_class: Type[MiddlewareMixin]) -> Callable: ...
|
||||||
def available_attrs(fn: Any): ...
|
def available_attrs(fn: Any): ...
|
||||||
def make_middleware_decorator(middleware_class: Type[MiddlewareMixin]) -> Callable: ...
|
def make_middleware_decorator(middleware_class: Type[MiddlewareMixin]) -> Callable: ...
|
||||||
@@ -17,5 +15,5 @@ def make_middleware_decorator(middleware_class: Type[MiddlewareMixin]) -> Callab
|
|||||||
class classproperty:
|
class classproperty:
|
||||||
fget: Optional[Callable] = ...
|
fget: Optional[Callable] = ...
|
||||||
def __init__(self, method: Optional[Callable] = ...) -> None: ...
|
def __init__(self, method: Optional[Callable] = ...) -> None: ...
|
||||||
def __get__(self, instance: Optional[LiveServerTestCase], cls: Type[LiveServerTestCase] = ...) -> str: ...
|
def __get__(self, instance: Any, cls: Optional[type] = ...) -> Any: ...
|
||||||
def getter(self, method: Callable) -> classproperty: ...
|
def getter(self, method: Callable) -> classproperty: ...
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import dataclasses
|
|||||||
from mypy.nodes import (
|
from mypy.nodes import (
|
||||||
ARG_STAR, ARG_STAR2, MDEF, Argument, CallExpr, ClassDef, Expression, IndexExpr, Lvalue, MemberExpr, MypyFile,
|
ARG_STAR, ARG_STAR2, MDEF, Argument, CallExpr, ClassDef, Expression, IndexExpr, Lvalue, MemberExpr, MypyFile,
|
||||||
NameExpr, StrExpr, SymbolTableNode, TypeInfo, Var,
|
NameExpr, StrExpr, SymbolTableNode, TypeInfo, Var,
|
||||||
)
|
ARG_POS)
|
||||||
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
|
||||||
@@ -255,10 +255,23 @@ def add_dummy_init_method(ctx: ClassDefContext) -> None:
|
|||||||
type_annotation=any, initializer=None, kind=ARG_STAR2)
|
type_annotation=any, initializer=None, kind=ARG_STAR2)
|
||||||
|
|
||||||
add_method(ctx, '__init__', [pos_arg, kw_arg], NoneTyp())
|
add_method(ctx, '__init__', [pos_arg, kw_arg], NoneTyp())
|
||||||
|
|
||||||
# mark as model class
|
# mark as model class
|
||||||
ctx.cls.info.metadata.setdefault('django', {})['generated_init'] = True
|
ctx.cls.info.metadata.setdefault('django', {})['generated_init'] = True
|
||||||
|
|
||||||
|
|
||||||
|
def add_get_set_attr_fallback_to_any(ctx: ClassDefContext):
|
||||||
|
any = AnyType(TypeOfAny.special_form)
|
||||||
|
|
||||||
|
name_arg = Argument(variable=Var('name', any),
|
||||||
|
type_annotation=any, initializer=None, kind=ARG_POS)
|
||||||
|
add_method(ctx, '__getattr__', [name_arg], any)
|
||||||
|
|
||||||
|
value_arg = Argument(variable=Var('value', any),
|
||||||
|
type_annotation=any, initializer=None, kind=ARG_POS)
|
||||||
|
add_method(ctx, '__setattr__', [name_arg, value_arg], any)
|
||||||
|
|
||||||
|
|
||||||
def process_model_class(ctx: ClassDefContext) -> None:
|
def process_model_class(ctx: ClassDefContext) -> None:
|
||||||
initializers = [
|
initializers = [
|
||||||
InjectAnyAsBaseForNestedMeta,
|
InjectAnyAsBaseForNestedMeta,
|
||||||
@@ -273,4 +286,4 @@ def process_model_class(ctx: ClassDefContext) -> None:
|
|||||||
add_dummy_init_method(ctx)
|
add_dummy_init_method(ctx)
|
||||||
|
|
||||||
# allow unspecified attributes for now
|
# allow unspecified attributes for now
|
||||||
ctx.cls.info.fallback_to_any = True
|
add_get_set_attr_fallback_to_any(ctx)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
pip install wheel twine
|
pip install wheel twine
|
||||||
python setup.py sdist bdist_wheel --universal
|
python setup.py sdist bdist_wheel
|
||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -59,7 +59,12 @@ IGNORED_ERRORS = {
|
|||||||
'Argument 1 to "loads" has incompatible type "Union[bytes, str, None]"; '
|
'Argument 1 to "loads" has incompatible type "Union[bytes, str, None]"; '
|
||||||
+ 'expected "Union[str, bytes, bytearray]"',
|
+ 'expected "Union[str, bytes, bytearray]"',
|
||||||
'Incompatible types in assignment (expression has type "None", variable has type Module)',
|
'Incompatible types in assignment (expression has type "None", variable has type Module)',
|
||||||
'note:'
|
'note:',
|
||||||
|
# Suppress false-positive error due to mypy being overly strict with base class compatibility checks even though
|
||||||
|
# objects/_default_manager are redefined in the subclass to be compatible with the base class definition.
|
||||||
|
# Can be removed when mypy issue is fixed: https://github.com/python/mypy/issues/2619
|
||||||
|
re.compile(r'Definition of "(objects|_default_manager)" in base class "[A-Za-z0-9]+" is incompatible with '
|
||||||
|
r'definition in base class "[A-Za-z0-9]+"'),
|
||||||
],
|
],
|
||||||
'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")'
|
||||||
@@ -213,11 +218,12 @@ IGNORED_ERRORS = {
|
|||||||
'Unexpected keyword argument "headline__startswith" for "in_bulk" of "QuerySet"',
|
'Unexpected keyword argument "headline__startswith" for "in_bulk" of "QuerySet"',
|
||||||
],
|
],
|
||||||
'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]")',
|
||||||
|
'Incompatible type for "parent" of "Child" (got "Child", expected "Union[Parent, Combinable]")'
|
||||||
],
|
],
|
||||||
'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"',
|
||||||
],
|
],
|
||||||
'model_forms': [
|
'model_forms': [
|
||||||
'Argument "instance" to "InvalidModelForm" has incompatible type "Type[Category]"; expected "Optional[Model]"',
|
'Argument "instance" to "InvalidModelForm" has incompatible type "Type[Category]"; expected "Optional[Model]"',
|
||||||
@@ -227,8 +233,14 @@ IGNORED_ERRORS = {
|
|||||||
'Incompatible types in assignment (expression has type "Type[Person]", variable has type',
|
'Incompatible types in assignment (expression has type "Type[Person]", variable has type',
|
||||||
'Unexpected keyword argument "name" for "Person"',
|
'Unexpected keyword argument "name" for "Person"',
|
||||||
'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]", '
|
re.compile(
|
||||||
+ 'base class "ImageFieldTestMixin" defined the type as "Type[PersonWithHeightAndWidth]")',
|
r'Incompatible types in assignment \(expression has type "Type\[.+?\]", base class "IntegerFieldTests"'
|
||||||
|
r' defined the type as "Type\[IntegerModel\]"\)'),
|
||||||
|
re.compile(r'Incompatible types in assignment \(expression has type "Type\[.+?\]", base class'
|
||||||
|
r' "ImageFieldTestMixin" defined the type as "Type\[PersonWithHeightAndWidth\]"\)'),
|
||||||
|
'Incompatible import of "Person"',
|
||||||
|
'Incompatible types in assignment (expression has type "FloatModel", variable has type '
|
||||||
|
'"Union[float, int, str, Combinable]")',
|
||||||
],
|
],
|
||||||
'model_formsets': [
|
'model_formsets': [
|
||||||
'Incompatible types in string interpolation (expression has type "object", '
|
'Incompatible types in string interpolation (expression has type "object", '
|
||||||
@@ -261,7 +273,7 @@ IGNORED_ERRORS = {
|
|||||||
'Argument 1 to "RunPython" has incompatible type "str"; expected "Callable[..., Any]"',
|
'Argument 1 to "RunPython" has incompatible type "str"; expected "Callable[..., Any]"',
|
||||||
'FakeLoader',
|
'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")'
|
'Unsupported operand types for - ("Set[Any]" and "None")',
|
||||||
],
|
],
|
||||||
'middleware_exceptions': [
|
'middleware_exceptions': [
|
||||||
'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any]"; expected "str"'
|
'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any]"; expected "str"'
|
||||||
@@ -282,7 +294,11 @@ IGNORED_ERRORS = {
|
|||||||
+ 'expected "Optional[Type[JSONEncoder]]"',
|
+ 'expected "Optional[Type[JSONEncoder]]"',
|
||||||
'for model "CITestModel"',
|
'for model "CITestModel"',
|
||||||
'Incompatible type for "field" of "IntegerArrayModel" (got "None", '
|
'Incompatible type for "field" of "IntegerArrayModel" (got "None", '
|
||||||
+ 'expected "Union[Sequence[int], Combinable]")'
|
+ 'expected "Union[Sequence[int], Combinable]")',
|
||||||
|
re.compile(r'Incompatible types in assignment \(expression has type "Type\[.+?\]", base class "UnaccentTest" '
|
||||||
|
r'defined the type as "Type\[CharFieldModel\]"\)'),
|
||||||
|
'Incompatible types in assignment (expression has type "Type[TextFieldModel]", base class "TrigramTest" '
|
||||||
|
'defined the type as "Type[CharFieldModel]")',
|
||||||
],
|
],
|
||||||
'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"')
|
||||||
@@ -291,6 +307,12 @@ IGNORED_ERRORS = {
|
|||||||
'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"',
|
'No overload variant of "values_list" of "QuerySet" matches argument types "str", "bool", "bool"',
|
||||||
|
'Unsupported operand types for & ("QuerySet[Author, Author]" and "QuerySet[Tag, Tag]")',
|
||||||
|
'Unsupported operand types for | ("QuerySet[Author, Author]" and "QuerySet[Tag, Tag]")',
|
||||||
|
'Incompatible types in assignment (expression has type "ObjectB", variable has type "ObjectA")',
|
||||||
|
'Incompatible types in assignment (expression has type "ObjectC", variable has type "ObjectA")',
|
||||||
|
'Incompatible type for "objectb" of "ObjectC" (got "ObjectA", expected'
|
||||||
|
' "Union[ObjectB, Combinable, None, None]")',
|
||||||
],
|
],
|
||||||
'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")'
|
||||||
@@ -303,6 +325,9 @@ IGNORED_ERRORS = {
|
|||||||
'"None" has no attribute "__iter__"',
|
'"None" has no attribute "__iter__"',
|
||||||
'has no attribute "read_by"'
|
'has no attribute "read_by"'
|
||||||
],
|
],
|
||||||
|
'proxy_model_inheritance': [
|
||||||
|
'Incompatible import of "ProxyModel"'
|
||||||
|
],
|
||||||
'signals': [
|
'signals': [
|
||||||
'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any, Optional[Any], Any]"; '
|
'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any, Optional[Any], Any]"; '
|
||||||
+ 'expected "Tuple[Any, Any, Any]"'
|
+ 'expected "Tuple[Any, Any, Any]"'
|
||||||
@@ -387,7 +412,8 @@ IGNORED_ERRORS = {
|
|||||||
'Incompatible types in assignment (expression has type "None", variable has type "int")',
|
'Incompatible types in assignment (expression has type "None", variable has type "int")',
|
||||||
],
|
],
|
||||||
'select_related_onetoone': [
|
'select_related_onetoone': [
|
||||||
'"None" has no attribute'
|
'"None" has no attribute',
|
||||||
|
'Incompatible types in assignment (expression has type "Parent2", variable has type "Parent1")',
|
||||||
],
|
],
|
||||||
'servers': [
|
'servers': [
|
||||||
re.compile('Argument [0-9] to "WSGIRequestHandler"')
|
re.compile('Argument [0-9] to "WSGIRequestHandler"')
|
||||||
|
|||||||
@@ -22,8 +22,5 @@ addopts =
|
|||||||
-s
|
-s
|
||||||
-v
|
-v
|
||||||
|
|
||||||
[bdist_wheel]
|
|
||||||
universal = 1
|
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
license_file = LICENSE.txt
|
license_file = LICENSE.txt
|
||||||
|
|||||||
6
setup.py
6
setup.py
@@ -21,7 +21,7 @@ with open('README.md', 'r') as f:
|
|||||||
readme = f.read()
|
readme = f.read()
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
'mypy>=0.670',
|
'mypy>=0.670,<0.700',
|
||||||
'typing-extensions'
|
'typing-extensions'
|
||||||
]
|
]
|
||||||
if sys.version_info[:2] < (3, 7):
|
if sys.version_info[:2] < (3, 7):
|
||||||
@@ -30,7 +30,7 @@ if sys.version_info[:2] < (3, 7):
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="django-stubs",
|
name="django-stubs",
|
||||||
version="0.10.0",
|
version="0.11.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',
|
||||||
@@ -39,7 +39,7 @@ setup(
|
|||||||
author="Maksim Kurnikov",
|
author="Maksim Kurnikov",
|
||||||
author_email="maxim.kurnikov@gmail.com",
|
author_email="maxim.kurnikov@gmail.com",
|
||||||
py_modules=[],
|
py_modules=[],
|
||||||
python_requires='>=3',
|
python_requires='>=3.6',
|
||||||
install_requires=dependencies,
|
install_requires=dependencies,
|
||||||
packages=['django-stubs', *find_packages()],
|
packages=['django-stubs', *find_packages()],
|
||||||
package_data={'django-stubs': find_stub_files('django-stubs')},
|
package_data={'django-stubs': find_stub_files('django-stubs')},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from django.db import models
|
|||||||
class MyModel(models.Model):
|
class MyModel(models.Model):
|
||||||
authors = models.Manager[MyModel]()
|
authors = models.Manager[MyModel]()
|
||||||
reveal_type(MyModel.authors) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel]'
|
reveal_type(MyModel.authors) # E: Revealed type is 'django.db.models.manager.Manager[main.MyModel]'
|
||||||
reveal_type(MyModel.objects) # E: Revealed type is 'Any'
|
MyModel.objects # E: "Type[MyModel]" has no attribute "objects"
|
||||||
[out]
|
[out]
|
||||||
|
|
||||||
[CASE test_model_objects_attribute_present_in_case_of_model_cls_passed_as_generic_parameter]
|
[CASE test_model_objects_attribute_present_in_case_of_model_cls_passed_as_generic_parameter]
|
||||||
|
|||||||
28
test-data/typecheck/model.test
Normal file
28
test-data/typecheck/model.test
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
[CASE test_model_subtype_relationship_and_getting_and_setting_attributes]
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class A(models.Model):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class B(models.Model):
|
||||||
|
b_attr = 1
|
||||||
|
pass
|
||||||
|
|
||||||
|
class C(A):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def service(a: A) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
a_instance = A()
|
||||||
|
b_instance = B()
|
||||||
|
reveal_type(b_instance.b_attr) # E: Revealed type is 'builtins.int'
|
||||||
|
|
||||||
|
|
||||||
|
reveal_type(b_instance.non_existent_attribute) # E: Revealed type is 'Any'
|
||||||
|
b_instance.non_existent_attribute = 2
|
||||||
|
|
||||||
|
service(b_instance) # E: Argument 1 to "service" has incompatible type "B"; expected "A"
|
||||||
|
|
||||||
|
c_instance = C()
|
||||||
|
service(c_instance)
|
||||||
@@ -27,12 +27,16 @@ class Parent1(models.Model):
|
|||||||
class Parent2(models.Model):
|
class Parent2(models.Model):
|
||||||
id2 = models.AutoField(primary_key=True)
|
id2 = models.AutoField(primary_key=True)
|
||||||
name2 = models.CharField(max_length=50)
|
name2 = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
# TODO: Remove the 2 expected errors on the next line once mypy issue https://github.com/python/mypy/issues/2619 is resolved:
|
||||||
class Child1(Parent1, Parent2):
|
class Child1(Parent1, Parent2):
|
||||||
value = models.IntegerField()
|
value = models.IntegerField()
|
||||||
class Child4(Child1):
|
class Child4(Child1):
|
||||||
value4 = models.IntegerField()
|
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]
|
[out]
|
||||||
|
main:10: error: Definition of "objects" in base class "Parent1" is incompatible with definition in base class "Parent2"
|
||||||
|
main:10: error: Definition of "_default_manager" in base class "Parent1" is incompatible with definition in base class "Parent2"
|
||||||
|
|
||||||
[CASE optional_primary_key_for_create_is_error]
|
[CASE optional_primary_key_for_create_is_error]
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|||||||
Reference in New Issue
Block a user