Skip to content

Gracefully handle unwanted types when creating fallback managers #1728

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

Merged
merged 1 commit into from
Sep 22, 2023
Merged
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
30 changes: 18 additions & 12 deletions mypy_django_plugin/transformers/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def get_generated_manager_info(self, manager_fullname: str, base_manager_fullnam
# Not a generated manager
return None

def get_or_create_manager_with_any_fallback(self, related_manager: bool = False) -> TypeInfo:
def get_or_create_manager_with_any_fallback(self, related_manager: bool = False) -> Optional[TypeInfo]:
"""
Create a Manager subclass with fallback to Any for unknown attributes
and methods. This is used for unresolved managers, where we don't know
Expand All @@ -121,11 +121,14 @@ def get_or_create_manager_with_any_fallback(self, related_manager: bool = False)
return manager_info

fallback_queryset = self.get_or_create_queryset_with_any_fallback()
if fallback_queryset is None:
return None
base_manager_fullname = (
fullnames.MANAGER_CLASS_FULLNAME if not related_manager else fullnames.RELATED_MANAGER_CLASS
)
base_manager_info = self.lookup_typeinfo(base_manager_fullname)
assert base_manager_info, f"Type info for {base_manager_fullname} missing"
if base_manager_info is None:
return None

base_manager = fill_typevars(base_manager_info)
assert isinstance(base_manager, Instance)
Expand Down Expand Up @@ -153,7 +156,7 @@ def get_or_create_manager_with_any_fallback(self, related_manager: bool = False)

return manager_info

def get_or_create_queryset_with_any_fallback(self) -> TypeInfo:
def get_or_create_queryset_with_any_fallback(self) -> Optional[TypeInfo]:
"""
Create a QuerySet subclass with fallback to Any for unknown attributes
and methods. This is used for the manager returned by the method above.
Expand All @@ -168,7 +171,8 @@ def get_or_create_queryset_with_any_fallback(self) -> TypeInfo:
return queryset_info

base_queryset_info = self.lookup_typeinfo(fullnames.QUERYSET_CLASS_FULLNAME)
assert base_queryset_info, f"Type info for {fullnames.QUERYSET_CLASS_FULLNAME} missing"
if base_queryset_info is None:
return None

base_queryset = fill_typevars(base_queryset_info)
assert isinstance(base_queryset, Instance)
Expand Down Expand Up @@ -346,11 +350,12 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:
# ignoring a more specialised manager not being resolved while still
# setting _some_ type
fallback_manager_info = self.get_or_create_manager_with_any_fallback()
self.add_new_node_to_model_class(
manager_name,
Instance(fallback_manager_info, [Instance(self.model_classdef.info, [])]),
is_classvar=True,
)
if fallback_manager_info is not None:
self.add_new_node_to_model_class(
manager_name,
Instance(fallback_manager_info, [Instance(self.model_classdef.info, [])]),
is_classvar=True,
)

# Find expression for e.g. `objects = SomeManager()`
manager_expr = self.get_manager_expression(manager_name)
Expand Down Expand Up @@ -493,9 +498,10 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None:
# See https://github.com/typeddjango/django-stubs/pull/993
# for more information on when this error can occur.
fallback_manager = self.get_or_create_manager_with_any_fallback(related_manager=True)
self.add_new_node_to_model_class(
attname, Instance(fallback_manager, [Instance(related_model_info, [])])
)
if fallback_manager is not None:
self.add_new_node_to_model_class(
attname, Instance(fallback_manager, [Instance(related_model_info, [])])
)
related_model_fullname = related_model_cls.__module__ + "." + related_model_cls.__name__
self.ctx.api.fail(
(
Expand Down