|
| 1 | +from mypy.types import AnyType, Instance |
| 2 | +from mypy.types import Type as MypyType |
| 3 | +from mypy.types import TypeOfAny |
| 4 | + |
| 5 | +from mypy_django_plugin.lib import chk_helpers, fullnames, helpers |
| 6 | + |
| 7 | + |
| 8 | +class QuerySetFilterTypecheckCallback(helpers.GetMethodCallback): |
| 9 | + def resolve_combinable_type(self, combinable_type: Instance) -> MypyType: |
| 10 | + if combinable_type.type.fullname != fullnames.F_EXPRESSION_FULLNAME: |
| 11 | + # Combinables aside from F expressions are unsupported |
| 12 | + return AnyType(TypeOfAny.explicit) |
| 13 | + |
| 14 | + return self.django_context.resolve_f_expression_type(combinable_type) |
| 15 | + |
| 16 | + def get_method_return_type(self) -> MypyType: |
| 17 | + lookup_kwargs = self.ctx.arg_names[1] |
| 18 | + provided_lookup_types = self.ctx.arg_types[1] |
| 19 | + |
| 20 | + if not self.callee_type.args or not isinstance(self.callee_type.args[0], Instance): |
| 21 | + return self.default_return_type |
| 22 | + |
| 23 | + model_cls_fullname = self.callee_type.args[0].type.fullname |
| 24 | + model_cls = self.django_context.get_model_class_by_fullname(model_cls_fullname) |
| 25 | + if model_cls is None: |
| 26 | + return self.default_return_type |
| 27 | + |
| 28 | + for lookup_kwarg, provided_type in zip(lookup_kwargs, provided_lookup_types): |
| 29 | + if lookup_kwarg is None: |
| 30 | + continue |
| 31 | + if (isinstance(provided_type, Instance) |
| 32 | + and provided_type.type.has_base('django.db.models.expressions.Combinable')): |
| 33 | + provided_type = self.resolve_combinable_type(provided_type) |
| 34 | + |
| 35 | + lookup_type = self.django_context.resolve_lookup_expected_type(self.ctx, model_cls, lookup_kwarg) |
| 36 | + # Managers as provided_type is not supported yet |
| 37 | + if (isinstance(provided_type, Instance) |
| 38 | + and helpers.has_any_of_bases(provided_type.type, (fullnames.MANAGER_CLASS_FULLNAME, |
| 39 | + fullnames.QUERYSET_CLASS_FULLNAME))): |
| 40 | + return self.default_return_type |
| 41 | + |
| 42 | + chk_helpers.check_types_compatible(self.ctx, |
| 43 | + expected_type=lookup_type, |
| 44 | + actual_type=provided_type, |
| 45 | + error_message=f'Incompatible type for lookup {lookup_kwarg!r}:') |
| 46 | + |
| 47 | + return self.default_return_type |
0 commit comments