From: Mike Bayer Date: Tue, 20 Jun 2023 19:24:38 +0000 (-0400) Subject: updates for mypy 1.4 X-Git-Tag: rel_1_4_49~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b39af62d10f7244f99635619ddb29a45359ace92;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 (cherry picked from commit f79d09221b1ec6cd6bc8d83d6e947db5f75c6d1c) --- 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 f88a960bd2..f3f44a4250 100644 --- a/lib/sqlalchemy/ext/mypy/infer.py +++ b/lib/sqlalchemy/ext/mypy/infer.py @@ -9,7 +9,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 @@ -454,8 +453,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 16b365e1ee..373fd4bfbc 100644 --- a/lib/sqlalchemy/ext/mypy/util.py +++ b/lib/sqlalchemy/ext/mypy/util.py @@ -10,6 +10,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 ARG_POS from mypy.nodes import CallExpr from mypy.nodes import ClassDef @@ -23,6 +25,7 @@ from mypy.nodes import NameExpr from mypy.nodes import Statement from mypy.nodes import SymbolTableNode 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 @@ -35,6 +38,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]) @@ -151,6 +159,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 cb04d1c739..be80043ca8 100644 --- a/test/ext/mypy/test_mypy_plugin_py3k.py +++ b/test/ext/mypy/test_mypy_plugin_py3k.py @@ -172,6 +172,9 @@ class MypyPluginTest(fixtures.TestBase): expected_errors = [] expected_re = re.compile(r"\s*# EXPECTED(_MYPY)?: (.+)") 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_: for num, line in enumerate(file_, 1): m = py_ver_re.match(line) @@ -191,6 +194,22 @@ class MypyPluginTest(fixtures.TestBase): is_mypy = bool(m.group(1)) expected_msg = m.group(2) expected_msg = re.sub(r"# noqa[:]? ?.*", "", m.group(2)) + + 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|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, + ) + expected_errors.append( (num, is_mypy, expected_msg.strip()) )