mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-07 04:34:29 +08:00
Allow to run from_queryset() with BaseManager, Manager (#271)
* allow to run from_queryset() with BaseManager, Manager * fix tests
This commit is contained in:
@@ -2,7 +2,7 @@ from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Ty
|
|||||||
|
|
||||||
from django.core.checks.messages import CheckMessage
|
from django.core.checks.messages import CheckMessage
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db.models.manager import Manager
|
from django.db.models.manager import BaseManager
|
||||||
from django.db.models.options import Options
|
from django.db.models.options import Options
|
||||||
|
|
||||||
_Self = TypeVar("_Self", bound="Model")
|
_Self = TypeVar("_Self", bound="Model")
|
||||||
@@ -13,9 +13,9 @@ class Model(metaclass=ModelBase):
|
|||||||
class DoesNotExist(Exception): ...
|
class DoesNotExist(Exception): ...
|
||||||
class MultipleObjectsReturned(Exception): ...
|
class MultipleObjectsReturned(Exception): ...
|
||||||
class Meta: ...
|
class Meta: ...
|
||||||
_default_manager: Manager[Model]
|
|
||||||
_meta: Options[Any]
|
_meta: Options[Any]
|
||||||
objects: Manager[Any]
|
_default_manager: BaseManager[Model]
|
||||||
|
objects: BaseManager[Any]
|
||||||
pk: Any = ...
|
pk: Any = ...
|
||||||
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]]: ...
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ FORM_MIXIN_CLASS_FULLNAME = 'django.views.generic.edit.FormMixin'
|
|||||||
|
|
||||||
MANAGER_CLASSES = {
|
MANAGER_CLASSES = {
|
||||||
MANAGER_CLASS_FULLNAME,
|
MANAGER_CLASS_FULLNAME,
|
||||||
RELATED_MANAGER_CLASS,
|
|
||||||
BASE_MANAGER_CLASS_FULLNAME,
|
BASE_MANAGER_CLASS_FULLNAME,
|
||||||
# QUERYSET_CLASS_FULLNAME
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RELATED_FIELDS_CLASSES = {
|
RELATED_FIELDS_CLASSES = {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from mypy.nodes import (
|
from mypy.nodes import (
|
||||||
GDEF, FuncDef, MemberExpr, NameExpr, StrExpr, SymbolTableNode, TypeInfo,
|
GDEF, FuncDef, MemberExpr, NameExpr, RefExpr, StrExpr, SymbolTableNode, TypeInfo,
|
||||||
)
|
)
|
||||||
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
|
||||||
@@ -10,9 +10,11 @@ from mypy_django_plugin.lib import 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:
|
||||||
semanal_api = helpers.get_semanal_api(ctx)
|
semanal_api = helpers.get_semanal_api(ctx)
|
||||||
|
|
||||||
assert isinstance(ctx.call.callee, MemberExpr)
|
callee = ctx.call.callee
|
||||||
assert isinstance(ctx.call.callee.expr, NameExpr)
|
assert isinstance(callee, MemberExpr)
|
||||||
base_manager_info = ctx.call.callee.expr.node
|
assert isinstance(callee.expr, RefExpr)
|
||||||
|
|
||||||
|
base_manager_info = callee.expr.node
|
||||||
if base_manager_info is None:
|
if base_manager_info is None:
|
||||||
if not semanal_api.final_iteration:
|
if not semanal_api.final_iteration:
|
||||||
semanal_api.defer()
|
semanal_api.defer()
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class AddManagers(ModelClassInitializer):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def is_any_parametrized_manager(self, typ: Instance) -> bool:
|
def is_any_parametrized_manager(self, typ: Instance) -> bool:
|
||||||
return typ.type.fullname == fullnames.MANAGER_CLASS_FULLNAME and isinstance(typ.args[0], AnyType)
|
return typ.type.fullname in fullnames.MANAGER_CLASSES and isinstance(typ.args[0], AnyType)
|
||||||
|
|
||||||
def get_generated_manager_mappings(self, base_manager_fullname: str) -> Dict[str, str]:
|
def get_generated_manager_mappings(self, base_manager_fullname: str) -> Dict[str, str]:
|
||||||
base_manager_info = self.lookup_typeinfo(base_manager_fullname)
|
base_manager_info = self.lookup_typeinfo(base_manager_fullname)
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ IGNORED_ERRORS = {
|
|||||||
'"Manager[Any]" has no attribute "args"',
|
'"Manager[Any]" has no attribute "args"',
|
||||||
'Dict entry 0 has incompatible type "Any"',
|
'Dict entry 0 has incompatible type "Any"',
|
||||||
'Argument 1 to "append" of "list" has incompatible type',
|
'Argument 1 to "append" of "list" has incompatible type',
|
||||||
'base class "Model" defined the type as "Manager[Any]"',
|
'base class "Model" defined the type as "BaseManager[Any]"',
|
||||||
'Argument 1 to "RunPython" has incompatible type "str"',
|
'Argument 1 to "RunPython" has incompatible type "str"',
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,4 +1,48 @@
|
|||||||
- case: test_from_queryset_returns_intersection_of_manager_and_queryset
|
- case: from_queryset_with_base_manager
|
||||||
|
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 ModelQuerySet(models.QuerySet):
|
||||||
|
def queryset_method(self) -> str:
|
||||||
|
return 'hello'
|
||||||
|
NewManager = BaseManager.from_queryset(ModelQuerySet)
|
||||||
|
class MyModel(models.Model):
|
||||||
|
objects = NewManager()
|
||||||
|
|
||||||
|
- case: from_queryset_with_manager
|
||||||
|
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
|
||||||
|
|
||||||
|
class ModelQuerySet(models.QuerySet):
|
||||||
|
def queryset_method(self) -> str:
|
||||||
|
return 'hello'
|
||||||
|
|
||||||
|
NewManager = models.Manager.from_queryset(ModelQuerySet)
|
||||||
|
class MyModel(models.Model):
|
||||||
|
objects = NewManager()
|
||||||
|
|
||||||
|
- case: from_queryset_returns_intersection_of_manager_and_queryset
|
||||||
main: |
|
main: |
|
||||||
from myapp.models import MyModel, NewManager
|
from myapp.models import MyModel, NewManager
|
||||||
reveal_type(NewManager()) # N: Revealed type is 'myapp.models.NewManager'
|
reveal_type(NewManager()) # N: Revealed type is 'myapp.models.NewManager'
|
||||||
@@ -24,7 +68,7 @@
|
|||||||
class MyModel(models.Model):
|
class MyModel(models.Model):
|
||||||
objects = NewManager()
|
objects = NewManager()
|
||||||
|
|
||||||
- case: test_from_queryset_with_class_name_provided
|
- case: from_queryset_with_class_name_provided
|
||||||
main: |
|
main: |
|
||||||
from myapp.models import MyModel, NewManager
|
from myapp.models import MyModel, NewManager
|
||||||
reveal_type(NewManager()) # N: Revealed type is 'myapp.models.NewManager'
|
reveal_type(NewManager()) # N: Revealed type is 'myapp.models.NewManager'
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
class Base(Generic[_T]):
|
class Base(Generic[_T]):
|
||||||
def __init__(self, model_cls: Type[_T]):
|
def __init__(self, model_cls: Type[_T]):
|
||||||
self.model_cls = model_cls
|
self.model_cls = model_cls
|
||||||
reveal_type(self.model_cls._default_manager) # N: Revealed type is 'django.db.models.manager.Manager[django.db.models.base.Model]'
|
reveal_type(self.model_cls._default_manager) # N: Revealed type is 'django.db.models.manager.BaseManager[django.db.models.base.Model]'
|
||||||
class MyModel(models.Model):
|
class MyModel(models.Model):
|
||||||
pass
|
pass
|
||||||
class Child(Base[MyModel]):
|
class Child(Base[MyModel]):
|
||||||
|
|||||||
Reference in New Issue
Block a user