mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-10 14:01:56 +08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c3dfcbc9f | ||
|
|
1196336e3b | ||
|
|
665f4d8ea1 | ||
|
|
b3ed9e4827 | ||
|
|
fb1593630a | ||
|
|
031d42a75d |
@@ -1,11 +1,24 @@
|
|||||||
def supports_color() -> bool: ...
|
def supports_color() -> bool: ...
|
||||||
|
|
||||||
class Style:
|
class Style:
|
||||||
def DEBUG(self, text: str) -> str: ...
|
def ERROR(self, text: str) -> str: ...
|
||||||
def INFO(self, text: str) -> str: ...
|
|
||||||
def SUCCESS(self, text: str) -> str: ...
|
def SUCCESS(self, text: str) -> str: ...
|
||||||
def WARNING(self, text: str) -> str: ...
|
def WARNING(self, text: str) -> str: ...
|
||||||
def ERROR(self, text: str) -> str: ...
|
def NOTICE(self, text: str) -> str: ...
|
||||||
|
def SQL_FIELD(self, text: str) -> str: ...
|
||||||
|
def SQL_COLTYPE(self, text: str) -> str: ...
|
||||||
|
def SQL_KEYWORD(self, text: str) -> str: ...
|
||||||
|
def SQL_TABLE(self, text: str) -> str: ...
|
||||||
|
def HTTP_INFO(self, text: str) -> str: ...
|
||||||
|
def HTTP_SUCCESS(self, text: str) -> str: ...
|
||||||
|
def HTTP_REDIRECT(self, text: str) -> str: ...
|
||||||
|
def HTTP_NOT_MODIFIED(self, text: str) -> str: ...
|
||||||
|
def HTTP_BAD_REQUEST(self, text: str) -> str: ...
|
||||||
|
def HTTP_NOT_FOUND(self, text: str) -> str: ...
|
||||||
|
def HTTP_SERVER_ERROR(self, text: str) -> str: ...
|
||||||
|
def MIGRATE_HEADING(self, text: str) -> str: ...
|
||||||
|
def MIGRATE_LABEL(self, text: str) -> str: ...
|
||||||
|
def ERROR_OUTPUT(self, text: str) -> str: ...
|
||||||
|
|
||||||
def make_style(config_string: str = ...) -> Style: ...
|
def make_style(config_string: str = ...) -> Style: ...
|
||||||
def no_style() -> Style: ...
|
def no_style() -> Style: ...
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ class CallableChoiceIterator:
|
|||||||
class ChoiceField(Field):
|
class ChoiceField(Field):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
choices: _FieldChoices = ...,
|
choices: Union[_FieldChoices, Callable[[], _FieldChoices]] = ...,
|
||||||
required: bool = ...,
|
required: bool = ...,
|
||||||
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
widget: Optional[Union[Widget, Type[Widget]]] = ...,
|
||||||
label: Optional[Any] = ...,
|
label: Optional[Any] = ...,
|
||||||
|
|||||||
@@ -327,6 +327,14 @@ def _prepare_new_method_arguments(node: FuncDef) -> Tuple[List[Argument], MypyTy
|
|||||||
def copy_method_to_another_class(ctx: ClassDefContext, self_type: Instance,
|
def copy_method_to_another_class(ctx: ClassDefContext, self_type: Instance,
|
||||||
new_method_name: str, method_node: FuncDef) -> None:
|
new_method_name: str, method_node: FuncDef) -> None:
|
||||||
arguments, return_type = _prepare_new_method_arguments(method_node)
|
arguments, return_type = _prepare_new_method_arguments(method_node)
|
||||||
|
|
||||||
|
semanal_api = get_semanal_api(ctx)
|
||||||
|
for argument in arguments:
|
||||||
|
if argument.type_annotation is not None:
|
||||||
|
argument.type_annotation = semanal_api.anal_type(argument.type_annotation)
|
||||||
|
if return_type is not None:
|
||||||
|
return_type = semanal_api.anal_type(return_type) or AnyType(TypeOfAny.unannotated)
|
||||||
|
|
||||||
add_method(ctx,
|
add_method(ctx,
|
||||||
new_method_name,
|
new_method_name,
|
||||||
args=arguments,
|
args=arguments,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from mypy.nodes import (
|
|||||||
from mypy.plugin import ClassDefContext, DynamicClassDefContext
|
from mypy.plugin import ClassDefContext, DynamicClassDefContext
|
||||||
from mypy.types import AnyType, Instance, TypeOfAny
|
from mypy.types import AnyType, Instance, TypeOfAny
|
||||||
|
|
||||||
from mypy_django_plugin.lib import helpers
|
from mypy_django_plugin.lib import fullnames, helpers
|
||||||
|
|
||||||
|
|
||||||
def create_new_manager_class_from_from_queryset_method(ctx: DynamicClassDefContext) -> None:
|
def create_new_manager_class_from_from_queryset_method(ctx: DynamicClassDefContext) -> None:
|
||||||
@@ -65,7 +65,11 @@ def create_new_manager_class_from_from_queryset_method(ctx: DynamicClassDefConte
|
|||||||
class_def_context = ClassDefContext(cls=new_manager_info.defn,
|
class_def_context = ClassDefContext(cls=new_manager_info.defn,
|
||||||
reason=ctx.call, api=semanal_api)
|
reason=ctx.call, api=semanal_api)
|
||||||
self_type = Instance(new_manager_info, [])
|
self_type = Instance(new_manager_info, [])
|
||||||
for name, sym in derived_queryset_info.names.items():
|
# we need to copy all methods in MRO before django.db.models.query.QuerySet
|
||||||
|
for class_mro_info in derived_queryset_info.mro:
|
||||||
|
if class_mro_info.fullname == fullnames.QUERYSET_CLASS_FULLNAME:
|
||||||
|
break
|
||||||
|
for name, sym in class_mro_info.names.items():
|
||||||
if isinstance(sym.node, FuncDef):
|
if isinstance(sym.node, FuncDef):
|
||||||
helpers.copy_method_to_another_class(class_def_context,
|
helpers.copy_method_to_another_class(class_def_context,
|
||||||
self_type,
|
self_type,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import Dict, Optional, Type, cast
|
from typing import Dict, List, Optional, Type, cast
|
||||||
|
|
||||||
from django.db.models.base import Model
|
from django.db.models.base import Model
|
||||||
from django.db.models.fields import DateField, DateTimeField
|
from django.db.models.fields import DateField, DateTimeField
|
||||||
@@ -58,6 +58,12 @@ class ModelClassInitializer:
|
|||||||
name=name,
|
name=name,
|
||||||
sym_type=typ)
|
sym_type=typ)
|
||||||
|
|
||||||
|
def add_new_class_for_current_module(self, name: str, bases: List[Instance]) -> TypeInfo:
|
||||||
|
current_module = self.api.modules[self.model_classdef.info.module_name]
|
||||||
|
new_class_info = helpers.add_new_class_for_module(current_module,
|
||||||
|
name=name, bases=bases)
|
||||||
|
return new_class_info
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
model_cls = self.django_context.get_model_class_by_fullname(self.model_classdef.fullname)
|
model_cls = self.django_context.get_model_class_by_fullname(self.model_classdef.fullname)
|
||||||
if model_cls is None:
|
if model_cls is None:
|
||||||
@@ -164,14 +170,12 @@ class AddManagers(ModelClassInitializer):
|
|||||||
[Instance(self.model_classdef.info, [])])
|
[Instance(self.model_classdef.info, [])])
|
||||||
bases.append(original_base)
|
bases.append(original_base)
|
||||||
|
|
||||||
current_module = self.api.modules[self.model_classdef.info.module_name]
|
new_manager_info = self.add_new_class_for_current_module(name, bases)
|
||||||
custom_manager_info = helpers.add_new_class_for_module(current_module,
|
|
||||||
name=name, bases=bases)
|
|
||||||
# copy fields to a new manager
|
# copy fields to a new manager
|
||||||
new_cls_def_context = ClassDefContext(cls=custom_manager_info.defn,
|
new_cls_def_context = ClassDefContext(cls=new_manager_info.defn,
|
||||||
reason=self.ctx.reason,
|
reason=self.ctx.reason,
|
||||||
api=self.api)
|
api=self.api)
|
||||||
custom_manager_type = Instance(custom_manager_info, [Instance(self.model_classdef.info, [])])
|
custom_manager_type = Instance(new_manager_info, [Instance(self.model_classdef.info, [])])
|
||||||
|
|
||||||
for name, sym in base_manager_info.names.items():
|
for name, sym in base_manager_info.names.items():
|
||||||
# replace self type with new class, if copying method
|
# replace self type with new class, if copying method
|
||||||
@@ -185,10 +189,10 @@ class AddManagers(ModelClassInitializer):
|
|||||||
new_sym = sym.copy()
|
new_sym = sym.copy()
|
||||||
if isinstance(new_sym.node, Var):
|
if isinstance(new_sym.node, Var):
|
||||||
new_var = Var(name, type=sym.type)
|
new_var = Var(name, type=sym.type)
|
||||||
new_var.info = custom_manager_info
|
new_var.info = new_manager_info
|
||||||
new_var._fullname = custom_manager_info.fullname + '.' + name
|
new_var._fullname = new_manager_info.fullname + '.' + name
|
||||||
new_sym.node = new_var
|
new_sym.node = new_var
|
||||||
custom_manager_info.names[name] = new_sym
|
new_manager_info.names[name] = new_sym
|
||||||
|
|
||||||
return custom_manager_type
|
return custom_manager_type
|
||||||
|
|
||||||
@@ -268,16 +272,31 @@ class AddRelatedManagers(ModelClassInitializer):
|
|||||||
|
|
||||||
if isinstance(relation, (ManyToOneRel, ManyToManyRel)):
|
if isinstance(relation, (ManyToOneRel, ManyToManyRel)):
|
||||||
try:
|
try:
|
||||||
manager_info = self.lookup_typeinfo_or_incomplete_defn_error(fullnames.RELATED_MANAGER_CLASS)
|
related_manager_info = self.lookup_typeinfo_or_incomplete_defn_error(fullnames.RELATED_MANAGER_CLASS) # noqa: E501
|
||||||
|
if 'objects' not in related_model_info.names:
|
||||||
|
raise helpers.IncompleteDefnException()
|
||||||
except helpers.IncompleteDefnException as exc:
|
except helpers.IncompleteDefnException as exc:
|
||||||
if not self.api.final_iteration:
|
if not self.api.final_iteration:
|
||||||
raise exc
|
raise exc
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
self.add_new_node_to_model_class(attname,
|
|
||||||
Instance(manager_info, [Instance(related_model_info, [])]))
|
# create new RelatedManager subclass
|
||||||
|
parametrized_related_manager_type = Instance(related_manager_info,
|
||||||
|
[Instance(related_model_info, [])])
|
||||||
|
default_manager_type = related_model_info.names['objects'].type
|
||||||
|
if (default_manager_type is None
|
||||||
|
or not isinstance(default_manager_type, Instance)
|
||||||
|
or default_manager_type.type.fullname == fullnames.MANAGER_CLASS_FULLNAME):
|
||||||
|
self.add_new_node_to_model_class(attname, parametrized_related_manager_type)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
name = related_model_cls.__name__ + '_' + 'RelatedManager'
|
||||||
|
bases = [parametrized_related_manager_type, default_manager_type]
|
||||||
|
new_related_manager_info = self.add_new_class_for_current_module(name, bases)
|
||||||
|
|
||||||
|
self.add_new_node_to_model_class(attname, Instance(new_related_manager_info, []))
|
||||||
|
|
||||||
|
|
||||||
class AddExtraFieldMethods(ModelClassInitializer):
|
class AddExtraFieldMethods(ModelClassInitializer):
|
||||||
def run_with_model_cls(self, model_cls: Type[Model]) -> None:
|
def run_with_model_cls(self, model_cls: Type[Model]) -> None:
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ IGNORED_ERRORS = {
|
|||||||
re.compile(r'"(HttpRequest|WSGIRequest)" has no attribute'),
|
re.compile(r'"(HttpRequest|WSGIRequest)" has no attribute'),
|
||||||
],
|
],
|
||||||
'many_to_many': [
|
'many_to_many': [
|
||||||
'(expression has type "List[Article]", variable has type "RelatedManager[Article]"',
|
'(expression has type "List[Article]", variable has type "Article_RelatedManager2',
|
||||||
'"add" of "RelatedManager" has incompatible type "Article"; expected "Union[Publication, int]"',
|
'"add" of "RelatedManager" has incompatible type "Article"; expected "Union[Publication, int]"',
|
||||||
],
|
],
|
||||||
'many_to_one': [
|
'many_to_one': [
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -28,7 +28,7 @@ dependencies = [
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="django-stubs",
|
name="django-stubs",
|
||||||
version="1.3.2",
|
version="1.3.3",
|
||||||
description='Mypy stubs for Django',
|
description='Mypy stubs for Django',
|
||||||
long_description=readme,
|
long_description=readme,
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
|
|||||||
@@ -648,3 +648,27 @@
|
|||||||
abstract = True
|
abstract = True
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
- case: related_manager_is_a_subclass_of_default_manager
|
||||||
|
main: |
|
||||||
|
from myapp.models import User
|
||||||
|
reveal_type(User().orders) # N: Revealed type is 'myapp.models.Order_RelatedManager'
|
||||||
|
reveal_type(User().orders.get()) # N: Revealed type is 'myapp.models.Order*'
|
||||||
|
reveal_type(User().orders.manager_method()) # N: Revealed type is 'builtins.int'
|
||||||
|
installed_apps:
|
||||||
|
- myapp
|
||||||
|
files:
|
||||||
|
- path: myapp/__init__.py
|
||||||
|
- path: myapp/models.py
|
||||||
|
content: |
|
||||||
|
from django.db import models
|
||||||
|
class User(models.Model):
|
||||||
|
pass
|
||||||
|
class OrderManager(models.Manager):
|
||||||
|
def manager_method(self) -> int:
|
||||||
|
pass
|
||||||
|
class Order(models.Model):
|
||||||
|
objects = OrderManager()
|
||||||
|
user = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='orders')
|
||||||
|
|
||||||
|
|||||||
@@ -94,3 +94,55 @@
|
|||||||
class MyModel(models.Model):
|
class MyModel(models.Model):
|
||||||
objects = NewManager()
|
objects = NewManager()
|
||||||
|
|
||||||
|
- case: from_queryset_with_class_inheritance
|
||||||
|
main: |
|
||||||
|
from myapp.models import MyModel
|
||||||
|
reveal_type(MyModel().objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
|
||||||
|
reveal_type(MyModel().objects.get()) # N: Revealed type is 'myapp.models.MyModel*'
|
||||||
|
reveal_type(MyModel().objects.queryset_method()) # N: Revealed type is 'builtins.str'
|
||||||
|
installed_apps:
|
||||||
|
- myapp
|
||||||
|
files:
|
||||||
|
- path: myapp/__init__.py
|
||||||
|
- path: myapp/models.py
|
||||||
|
content: |
|
||||||
|
from django.db import models
|
||||||
|
from django.db.models.manager import BaseManager
|
||||||
|
class BaseQuerySet(models.QuerySet):
|
||||||
|
def queryset_method(self) -> str:
|
||||||
|
return 'hello'
|
||||||
|
class ModelQuerySet(BaseQuerySet):
|
||||||
|
pass
|
||||||
|
|
||||||
|
NewManager = BaseManager.from_queryset(ModelQuerySet)
|
||||||
|
class MyModel(models.Model):
|
||||||
|
objects = NewManager()
|
||||||
|
|
||||||
|
- case: from_queryset_with_manager_in_another_directory_and_imports
|
||||||
|
main: |
|
||||||
|
from myapp.models import MyModel
|
||||||
|
reveal_type(MyModel().objects) # N: Revealed type is 'myapp.models.MyModel_NewManager[myapp.models.MyModel]'
|
||||||
|
reveal_type(MyModel().objects.get()) # N: Revealed type is 'myapp.models.MyModel*'
|
||||||
|
reveal_type(MyModel().objects.queryset_method) # N: Revealed type is 'def (param: Union[builtins.str, None] =) -> Union[builtins.str, None]'
|
||||||
|
reveal_type(MyModel().objects.queryset_method('str')) # N: Revealed type is 'Union[builtins.str, None]'
|
||||||
|
installed_apps:
|
||||||
|
- myapp
|
||||||
|
files:
|
||||||
|
- path: myapp/__init__.py
|
||||||
|
- path: myapp/models.py
|
||||||
|
content: |
|
||||||
|
from django.db import models
|
||||||
|
from myapp.managers import NewManager
|
||||||
|
|
||||||
|
class MyModel(models.Model):
|
||||||
|
objects = NewManager()
|
||||||
|
- path: myapp/managers.py
|
||||||
|
content: |
|
||||||
|
from typing import Optional
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class ModelQuerySet(models.QuerySet):
|
||||||
|
def queryset_method(self, param: Optional[str] = None) -> Optional[str]:
|
||||||
|
return param
|
||||||
|
|
||||||
|
NewManager = models.Manager.from_queryset(ModelQuerySet)
|
||||||
|
|||||||
Reference in New Issue
Block a user