From 1196336e3b238a67115548bda805465bd37ece93 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 17 Dec 2019 19:19:31 +0300 Subject: [PATCH] Perform `anal_type` for arguments and return type when copying methods to another class (#279) * Found the reproducible test case * fix import resolution for method copy * remove irrelevant parts from test * fix mypy errors Co-authored-by: Boger --- mypy_django_plugin/lib/helpers.py | 8 +++++ .../managers/querysets/test_from_queryset.yml | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/mypy_django_plugin/lib/helpers.py b/mypy_django_plugin/lib/helpers.py index d428f9ab3..9ff77f093 100644 --- a/mypy_django_plugin/lib/helpers.py +++ b/mypy_django_plugin/lib/helpers.py @@ -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, new_method_name: str, method_node: FuncDef) -> None: 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, new_method_name, args=arguments, diff --git a/test-data/typecheck/managers/querysets/test_from_queryset.yml b/test-data/typecheck/managers/querysets/test_from_queryset.yml index 8c339d6e4..15628442b 100644 --- a/test-data/typecheck/managers/querysets/test_from_queryset.yml +++ b/test-data/typecheck/managers/querysets/test_from_queryset.yml @@ -117,3 +117,32 @@ 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)