From 1143a7394f0d1c28ab158d48b9a566ae32dce779 Mon Sep 17 00:00:00 2001 From: Kacper Szmigiel Date: Sun, 12 Jul 2020 12:12:30 +0200 Subject: [PATCH 1/5] additional defer() to offset the effect of using the type before declaring --- mypy_django_plugin/lib/helpers.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mypy_django_plugin/lib/helpers.py b/mypy_django_plugin/lib/helpers.py index d6d7f9c67..f8e46ec88 100644 --- a/mypy_django_plugin/lib/helpers.py +++ b/mypy_django_plugin/lib/helpers.py @@ -343,6 +343,7 @@ def copy_method_to_another_class(ctx: ClassDefContext, self_type: Instance, arguments = [] bound_return_type = semanal_api.anal_type(method_type.ret_type, allow_placeholder=True) + assert bound_return_type is not None if isinstance(bound_return_type, PlaceholderNode): @@ -352,8 +353,13 @@ def copy_method_to_another_class(ctx: ClassDefContext, self_type: Instance, method_type.arg_types[1:], method_node.arguments[1:]): bound_arg_type = semanal_api.anal_type(arg_type, allow_placeholder=True) - assert bound_arg_type is not None + + if bound_arg_type is None and not semanal_api.final_iteration: + semanal_api.defer() + return + assert bound_arg_type is not None + if isinstance(bound_arg_type, PlaceholderNode): return From c5bbc506569e5d95db7dd4c356eab50fa0dbcac3 Mon Sep 17 00:00:00 2001 From: Kacper Szmigiel Date: Sun, 12 Jul 2020 12:47:27 +0200 Subject: [PATCH 2/5] linter fix --- mypy_django_plugin/lib/helpers.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mypy_django_plugin/lib/helpers.py b/mypy_django_plugin/lib/helpers.py index f8e46ec88..493db40e5 100644 --- a/mypy_django_plugin/lib/helpers.py +++ b/mypy_django_plugin/lib/helpers.py @@ -352,14 +352,13 @@ def copy_method_to_another_class(ctx: ClassDefContext, self_type: Instance, for arg_name, arg_type, original_argument in zip(method_type.arg_names[1:], method_type.arg_types[1:], method_node.arguments[1:]): - bound_arg_type = semanal_api.anal_type(arg_type, allow_placeholder=True) - + bound_arg_type = semanal_api.anal_type(arg_type, allow_placeholder=True) if bound_arg_type is None and not semanal_api.final_iteration: semanal_api.defer() return assert bound_arg_type is not None - + if isinstance(bound_arg_type, PlaceholderNode): return From a323d7884eced219a7f3e484860e4cf9dca64863 Mon Sep 17 00:00:00 2001 From: Kacper Szmigiel Date: Sun, 12 Jul 2020 13:01:35 +0200 Subject: [PATCH 3/5] linter fix --- mypy_django_plugin/lib/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy_django_plugin/lib/helpers.py b/mypy_django_plugin/lib/helpers.py index 493db40e5..066957cd5 100644 --- a/mypy_django_plugin/lib/helpers.py +++ b/mypy_django_plugin/lib/helpers.py @@ -352,7 +352,7 @@ def copy_method_to_another_class(ctx: ClassDefContext, self_type: Instance, for arg_name, arg_type, original_argument in zip(method_type.arg_names[1:], method_type.arg_types[1:], method_node.arguments[1:]): - bound_arg_type = semanal_api.anal_type(arg_type, allow_placeholder=True) + bound_arg_type = semanal_api.anal_type(arg_type, allow_placeholder=True) if bound_arg_type is None and not semanal_api.final_iteration: semanal_api.defer() return From 649895414c887a6138d3ea9eb71fed0978c62920 Mon Sep 17 00:00:00 2001 From: Kacper Szmigiel Date: Sun, 12 Jul 2020 13:11:40 +0200 Subject: [PATCH 4/5] linter fix --- mypy_django_plugin/lib/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy_django_plugin/lib/helpers.py b/mypy_django_plugin/lib/helpers.py index 066957cd5..ee0cf61d1 100644 --- a/mypy_django_plugin/lib/helpers.py +++ b/mypy_django_plugin/lib/helpers.py @@ -352,7 +352,7 @@ def copy_method_to_another_class(ctx: ClassDefContext, self_type: Instance, for arg_name, arg_type, original_argument in zip(method_type.arg_names[1:], method_type.arg_types[1:], method_node.arguments[1:]): - bound_arg_type = semanal_api.anal_type(arg_type, allow_placeholder=True) + bound_arg_type = semanal_api.anal_type(arg_type, allow_placeholder=True) if bound_arg_type is None and not semanal_api.final_iteration: semanal_api.defer() return From 35049ee2416180e9fb9fb41e17ba97040c90e573 Mon Sep 17 00:00:00 2001 From: Kacper Szmigiel Date: Mon, 13 Jul 2020 14:33:10 +0200 Subject: [PATCH 5/5] test case --- .../typecheck/managers/test_managers.yml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test-data/typecheck/managers/test_managers.yml b/test-data/typecheck/managers/test_managers.yml index 82206d645..6018938fa 100644 --- a/test-data/typecheck/managers/test_managers.yml +++ b/test-data/typecheck/managers/test_managers.yml @@ -335,3 +335,25 @@ objects = MyManager() class ChildUser(models.Model): objects = MyManager() + +- case: custom_manager_annotate_method_before_type_declaration + main: | + from myapp.models import ModelA, ModelB, ManagerA + reveal_type(ModelA.objects) # N: Revealed type is 'myapp.models.ModelA_ManagerA1[myapp.models.ModelA]' + reveal_type(ModelA.objects.do_something) # N: Revealed type is 'def (other_obj: myapp.models.ModelB) -> builtins.str' + installed_apps: + - myapp + files: + - path: myapp/__init__.py + - path: myapp/models.py + content: | + from django.db import models + class ManagerA(models.Manager): + def do_something(self, other_obj: "ModelB") -> str: + return 'test' + class ModelA(models.Model): + title = models.TextField() + objects = ManagerA() + class ModelB(models.Model): + movie = models.TextField() +