From 8f30d9ac7367b4868fc1a22cd818de6e0a379b08 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Thu, 9 May 2024 18:06:27 +0300 Subject: [PATCH] Increase priority of mypy internal Django settings import (#2127) As discussed in https://github.com/typeddjango/django-stubs/discussions/2097#discussioncomment-9321035: * django-stubs 5.0.0 introduces new cases of the "Import cycle from Django settings module prevents type inference" error that did not occur in 4.2.7. * This was bisected down to the change in commit e517a1fb2bcdad20cc50930c43b285cb0650f292 (https://github.com/typeddjango/django-stubs/pull/2024). * Updated the priority of internal settings import to mypy's `PRI_HIGH` level. Related commit a10f8aa588d852ad5c14e57c5db068fd4e1ed128 (https://github.com/typeddjango/django-stubs/pull/2098) --- mypy_django_plugin/main.py | 8 +++---- tests/typecheck/conf/test_settings.yml | 30 +++++++++++++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/mypy_django_plugin/main.py b/mypy_django_plugin/main.py index 7dc431e0c..9f56ed89c 100644 --- a/mypy_django_plugin/main.py +++ b/mypy_django_plugin/main.py @@ -3,7 +3,7 @@ from functools import partial from typing import Any, Callable, Dict, List, Optional, Tuple, Type -from mypy.build import PRI_MYPY +from mypy.build import PRI_HIGH, PRI_MYPY from mypy.modulefinder import mypy_path from mypy.nodes import MypyFile, TypeInfo from mypy.options import Options @@ -99,14 +99,14 @@ def _get_typeinfo_or_none(self, class_name: str) -> Optional[TypeInfo]: return sym.node return None - def _new_dependency(self, module: str) -> Tuple[int, str, int]: + def _new_dependency(self, module: str, priority: int = PRI_MYPY) -> Tuple[int, str, int]: fake_lineno = -1 - return (PRI_MYPY, module, fake_lineno) + return (priority, module, fake_lineno) def get_additional_deps(self, file: MypyFile) -> List[Tuple[int, str, int]]: # for settings if file.fullname == "django.conf" and self.django_context.django_settings_module: - return [self._new_dependency(self.django_context.django_settings_module)] + return [self._new_dependency(self.django_context.django_settings_module, PRI_HIGH)] # for values / values_list if file.fullname == "django.db.models": diff --git a/tests/typecheck/conf/test_settings.yml b/tests/typecheck/conf/test_settings.yml index b825c148f..2dcfbf8ad 100644 --- a/tests/typecheck/conf/test_settings.yml +++ b/tests/typecheck/conf/test_settings.yml @@ -1,22 +1,36 @@ - case: test_setting_circular_import main: | from myapp import lib - custom_settings: | - from myapp.lib import function_returning_int - - IMMEDIATE_VALUE = 123 - CIRCULAR_WITHOUT_HINT = function_returning_int() - CIRCULAR_WITH_HINT: int = function_returning_int() + mypy_config: | + [mypy.plugins.django-stubs] + django_settings_module = myapp.settings files: - path: myapp/__init__.py + - path: myapp/settings.py + content: | + from myapp.lib import function_returning_int, const_with_circular_import + + IMMEDIATE_VALUE = 123 + CIRCULAR_WITH_HINT: int = function_returning_int() + CIRCULAR_WITHOUT_HINT_FUNCTION = function_returning_int() + CIRCULAR_WITHOUT_HINT_CONST = const_with_circular_import - path: myapp/lib.py content: | - from django.conf import settings + from typing import TYPE_CHECKING + import django.conf + + settings = django.conf.settings def test() -> None: reveal_type(settings.IMMEDIATE_VALUE) # N: Revealed type is "builtins.int" - reveal_type(settings.CIRCULAR_WITHOUT_HINT) # E: Import cycle from Django settings module prevents type inference for 'CIRCULAR_WITHOUT_HINT' [misc] # N: Revealed type is "Any" reveal_type(settings.CIRCULAR_WITH_HINT) # N: Revealed type is "builtins.int" + reveal_type(settings.CIRCULAR_WITHOUT_HINT_FUNCTION) # E: Import cycle from Django settings module prevents type inference for 'CIRCULAR_WITHOUT_HINT_FUNCTION' [misc] # N: Revealed type is "Any" + reveal_type(settings.CIRCULAR_WITHOUT_HINT_CONST) # E: Import cycle from Django settings module prevents type inference for 'CIRCULAR_WITHOUT_HINT_CONST' [misc] # N: Revealed type is "Any" def function_returning_int() -> int: return 42 + + if TYPE_CHECKING: + const_with_circular_import = settings.IMMEDIATE_VALUE + else: + const_with_circular_import = 0