Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lookup manager type via mro #2276

Merged
merged 3 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions mypy_django_plugin/transformers/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:

incomplete_manager_defs = set()
for manager_name, manager in model_cls._meta.managers_map.items():
manager_node = self.model_classdef.info.names.get(manager_name, None)
manager_node = self.model_classdef.info.get(manager_name)
manager_fullname = helpers.get_class_fullname(manager.__class__)
manager_info = self.lookup_manager(manager_fullname, manager)

Expand All @@ -343,7 +343,8 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:
incomplete_manager_defs.add(manager_name)
continue

manager_type = Instance(manager_info, [Instance(self.model_classdef.info, [])])
assert self.model_classdef.info.self_type is not None
manager_type = Instance(manager_info, [self.model_classdef.info.self_type])
self.add_new_node_to_model_class(manager_name, manager_type, is_classvar=True)

if incomplete_manager_defs:
Expand All @@ -359,9 +360,10 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:
# setting _some_ type
fallback_manager_info = self.get_or_create_manager_with_any_fallback()
if fallback_manager_info is not None:
assert self.model_classdef.info.self_type is not None
self.add_new_node_to_model_class(
manager_name,
Instance(fallback_manager_info, [Instance(self.model_classdef.info, [])]),
Instance(fallback_manager_info, [self.model_classdef.info.self_type]),
is_classvar=True,
)

Expand Down
1 change: 0 additions & 1 deletion tests/typecheck/managers/test_managers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,6 @@
myapp/models:23: error: Could not resolve manager type for "myapp.models.TwoUnresolvable.objects" [django-manager-missing]
myapp/models:24: error: Could not resolve manager type for "myapp.models.TwoUnresolvable.second_objects" [django-manager-missing]
myapp/models:27: error: Could not resolve manager type for "myapp.models.AbstractUnresolvable.objects" [django-manager-missing]
myapp/models:32: error: Could not resolve manager type for "myapp.models.InvisibleUnresolvable.objects" [django-manager-missing]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes sense to me at least -- we're no longer redefining an objects here because the base class already has an UnknownManager[Self] definition

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine IMO. The removal here goes away in my changes in #2252 too

myapp/models:36: note: Revealed type is "django.db.models.manager.Manager[myapp.models.User]"
myapp/models:37: note: Revealed type is "django.db.models.manager.Manager[myapp.models.User]"
myapp/models:39: note: Revealed type is "myapp.models.UnknownManager[myapp.models.Booking]"
Expand Down
41 changes: 41 additions & 0 deletions tests/typecheck/models/test_inheritance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,44 @@
abstract = True
class User(Mixin1, Mixin2):
name = models.TextField()

- case: test_manager_typevar_through_bounds
main: |
from myapp.models import ResultProcessorConcrete
reveal_type(ResultProcessorConcrete().f()) # N: Revealed type is "myapp.models.Concrete"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from __future__ import annotations

from django.db.models import Model
from django.db.models.manager import Manager
from typing import TypeVar, Generic, ClassVar
sobolevn marked this conversation as resolved.
Show resolved Hide resolved
from typing_extensions import Self

M = TypeVar("M", bound=Model, covariant=True)

class BaseManager(Manager[M]): ...

class Base(Model):
custom_objects: ClassVar[BaseManager[Self]] = BaseManager()

class Bound(Base): pass

T = TypeVar("T", bound=Bound)

class ResultProcessorBase(Generic[T]):
@property
def model_cls(self) -> type[T]:
sobolevn marked this conversation as resolved.
Show resolved Hide resolved
raise NotImplementedError

def f(self) -> T:
return self.model_cls.custom_objects.get()

class Concrete(Bound): pass

class ResultProcessorConcrete(ResultProcessorBase[Concrete]):
pass
Loading