From: Mike Bayer Date: Tue, 20 Jun 2023 19:24:38 +0000 (-0400) Subject: updates for mypy 1.4 X-Git-Tag: rel_2_0_17~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f79d09221b1ec6cd6bc8d83d6e947db5f75c6d1c;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git updates for mypy 1.4 mypy 1.4 is reporting new style types list[], tuple[], etc. as well as "x | None" for optional. they also added one argument for format_type(). This is for 1.4 backport as well Change-Id: I68084199858e9da901641d6036780437bcf5f2d6 --- diff --git a/doc/build/changelog/unreleased_14/mypy14.rst b/doc/build/changelog/unreleased_14/mypy14.rst new file mode 100644 index 0000000000..97c37514f8 --- /dev/null +++ b/doc/build/changelog/unreleased_14/mypy14.rst @@ -0,0 +1,5 @@ +.. change:: + :tags: bug, ext + :versions: 2.0.17 + + Fixed issue in mypy plugin for use with mypy 1.4. diff --git a/lib/sqlalchemy/ext/mypy/infer.py b/lib/sqlalchemy/ext/mypy/infer.py index 3313795935..e8345d09ae 100644 --- a/lib/sqlalchemy/ext/mypy/infer.py +++ b/lib/sqlalchemy/ext/mypy/infer.py @@ -11,7 +11,6 @@ from typing import Optional from typing import Sequence from mypy.maptype import map_instance_to_supertype -from mypy.messages import format_type from mypy.nodes import AssignmentStmt from mypy.nodes import CallExpr from mypy.nodes import Expression @@ -489,8 +488,8 @@ def _infer_type_from_left_and_inferred_right( api, msg.format( node.name, - format_type(orig_left_hand_type), - format_type(effective_type), + util.format_type(orig_left_hand_type, api.options), + util.format_type(effective_type, api.options), ), node, ) diff --git a/lib/sqlalchemy/ext/mypy/util.py b/lib/sqlalchemy/ext/mypy/util.py index c3771dbc5c..fe44021236 100644 --- a/lib/sqlalchemy/ext/mypy/util.py +++ b/lib/sqlalchemy/ext/mypy/util.py @@ -19,6 +19,8 @@ from typing import Type as TypingType from typing import TypeVar from typing import Union +from mypy import version +from mypy.messages import format_type as _mypy_format_type from mypy.nodes import CallExpr from mypy.nodes import ClassDef from mypy.nodes import CLASSDEF_NO_INFO @@ -33,6 +35,7 @@ from mypy.nodes import Statement from mypy.nodes import SymbolTableNode from mypy.nodes import TypeAlias from mypy.nodes import TypeInfo +from mypy.options import Options from mypy.plugin import ClassDefContext from mypy.plugin import DynamicClassDefContext from mypy.plugin import SemanticAnalyzerPluginInterface @@ -47,6 +50,11 @@ from mypy.types import TypeVarType from mypy.types import UnboundType from mypy.types import UnionType +_vers = tuple( + [int(x) for x in version.__version__.split(".") if re.match(r"^\d+$", x)] +) +mypy_14 = _vers >= (1, 4) + _TArgType = TypeVar("_TArgType", bound=Union[CallExpr, NameExpr]) @@ -163,6 +171,13 @@ def get_mapped_attributes( return attributes +def format_type(typ_: Type, options: Options) -> str: + if mypy_14: + return _mypy_format_type(typ_, options) # type: ignore + else: + return _mypy_format_type(typ_) # type: ignore + + def set_mapped_attributes( info: TypeInfo, attributes: List[SQLAlchemyAttribute] ) -> None: diff --git a/test/ext/mypy/test_mypy_plugin_py3k.py b/test/ext/mypy/test_mypy_plugin_py3k.py index 6a04f2730a..4440a16e45 100644 --- a/test/ext/mypy/test_mypy_plugin_py3k.py +++ b/test/ext/mypy/test_mypy_plugin_py3k.py @@ -207,6 +207,9 @@ class MypyPluginTest(fixtures.TestBase): expected_messages = [] expected_re = re.compile(r"\s*# EXPECTED(_MYPY)?(_RE)?(_TYPE)?: (.+)") py_ver_re = re.compile(r"^#\s*PYTHON_VERSION\s?>=\s?(\d+\.\d+)") + + from sqlalchemy.ext.mypy.util import mypy_14 + with open(path) as file_: current_assert_messages = [] for num, line in enumerate(file_, 1): @@ -229,6 +232,7 @@ class MypyPluginTest(fixtures.TestBase): is_type = bool(m.group(3)) expected_msg = re.sub(r"# noqa[:]? ?.*", "", m.group(4)) + if is_type: if not is_re: # the goal here is that we can cut-and-paste @@ -267,6 +271,23 @@ class MypyPluginTest(fixtures.TestBase): is_mypy = is_re = True expected_msg = f'Revealed type is "{expected_msg}"' + + if mypy_14: + # skip first character which could be capitalized + # "List item x not found" type of message + expected_msg = expected_msg[0] + re.sub( + r"\b(List|Tuple|Dict|Set)\b" + if is_type + else r"\b(List|Tuple|Dict|Set|Type)\b", + lambda m: m.group(1).lower(), + expected_msg[1:], + ) + + expected_msg = re.sub( + r"Optional\[(.*?)\]", + lambda m: f"{m.group(1)} | None", + expected_msg, + ) current_assert_messages.append( (is_mypy, is_re, expected_msg.strip()) )