From: Bryan Forbes Date: Mon, 12 Apr 2021 21:24:37 +0000 (-0500) Subject: Fix OrderingList handling X-Git-Tag: rel_1_4_8~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d3c3982100a617623c92b41799b19f27448a1574;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Fix OrderingList handling Revised the fix for ``OrderingList`` from version 1.4.7 which was testing against the incorrect API. Fixes: #6205 Change-Id: I1d3f8b6534b70ae000294c2a67f08117cb77ee99 --- diff --git a/doc/build/changelog/unreleased_14/6205.rst b/doc/build/changelog/unreleased_14/6205.rst new file mode 100644 index 0000000000..8a901bb88e --- /dev/null +++ b/doc/build/changelog/unreleased_14/6205.rst @@ -0,0 +1,6 @@ +.. change:: + :tags: bug, mypy + :tickets: 6205 + + Revised the fix for ``OrderingList`` from version 1.4.7 which was testing + against the incorrect API. diff --git a/lib/sqlalchemy/ext/mypy/infer.py b/lib/sqlalchemy/ext/mypy/infer.py index 7915c3ae2d..d734d588e5 100644 --- a/lib/sqlalchemy/ext/mypy/infer.py +++ b/lib/sqlalchemy/ext/mypy/infer.py @@ -13,6 +13,7 @@ from mypy.messages import format_type from mypy.nodes import AssignmentStmt from mypy.nodes import CallExpr from mypy.nodes import Expression +from mypy.nodes import FuncDef from mypy.nodes import MemberExpr from mypy.nodes import NameExpr from mypy.nodes import RefExpr @@ -22,6 +23,7 @@ from mypy.nodes import Var from mypy.plugin import SemanticAnalyzerPluginInterface from mypy.subtypes import is_subtype from mypy.types import AnyType +from mypy.types import CallableType from mypy.types import get_proper_type from mypy.types import Instance from mypy.types import NoneType @@ -125,6 +127,26 @@ def _infer_type_from_relationship( python_type_for_type = Instance( collection_cls_arg.node, [python_type_for_type] ) + elif ( + isinstance(collection_cls_arg, NameExpr) + and isinstance(collection_cls_arg.node, FuncDef) + and collection_cls_arg.node.type is not None + ): + if python_type_for_type is not None: + # this can still be overridden by the left hand side + # within _infer_Type_from_left_and_inferred_right + + # TODO: handle mypy.types.Overloaded + if isinstance(collection_cls_arg.node.type, CallableType): + rt = get_proper_type(collection_cls_arg.node.type.ret_type) + + if isinstance(rt, CallableType): + callable_ret_type = get_proper_type(rt.ret_type) + if isinstance(callable_ret_type, Instance): + python_type_for_type = Instance( + callable_ret_type.type, + [python_type_for_type], + ) else: util.fail( api, diff --git a/setup.cfg b/setup.cfg index b0eebb2855..001a38e30f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -127,6 +127,7 @@ ignore_errors = True [mypy-sqlalchemy.ext.mypy.*] ignore_errors = False + [sqla_testing] requirement_cls = test.requirements:DefaultRequirements profile_file = test/profiles.txt diff --git a/test/ext/mypy/files/orderinglist1.py b/test/ext/mypy/files/orderinglist1.py index cb06ba492f..661d55a7b6 100644 --- a/test/ext/mypy/files/orderinglist1.py +++ b/test/ext/mypy/files/orderinglist1.py @@ -1,7 +1,7 @@ from sqlalchemy import Column from sqlalchemy import ForeignKey from sqlalchemy import Integer -from sqlalchemy.ext.orderinglist import OrderingList +from sqlalchemy.ext.orderinglist import ordering_list from sqlalchemy.orm import registry from sqlalchemy.orm import relationship @@ -14,7 +14,7 @@ class A: id = Column(Integer, primary_key=True) # EXPECTED: Can't infer type from ORM mapped expression assigned to attribute 'parents'; please specify a Python type or Mapped[] on the left hand side. # noqa - parents = relationship("A", collection_class=OrderingList("ordering")) + parents = relationship("A", collection_class=ordering_list("ordering")) parent_id = Column(Integer, ForeignKey("a.id")) ordering = Column(Integer) diff --git a/test/ext/mypy/files/orderinglist2.py b/test/ext/mypy/files/orderinglist2.py index 2a1623e5c8..eb50c5391b 100644 --- a/test/ext/mypy/files/orderinglist2.py +++ b/test/ext/mypy/files/orderinglist2.py @@ -3,7 +3,7 @@ from typing import List from sqlalchemy import Column from sqlalchemy import ForeignKey from sqlalchemy import Integer -from sqlalchemy.ext.orderinglist import OrderingList +from sqlalchemy.ext.orderinglist import ordering_list from sqlalchemy.orm import registry from sqlalchemy.orm import relationship @@ -31,10 +31,10 @@ class A: __tablename__ = "a" id = Column(Integer, primary_key=True) - bs = relationship(B, collection_class=OrderingList("ordering")) + bs = relationship(B, collection_class=ordering_list("ordering")) bs_w_list: List[B] = relationship( - B, collection_class=OrderingList("ordering") + B, collection_class=ordering_list("ordering") ) # EXPECTED: Left hand assignment 'cs: "List[B]"' not compatible with ORM mapped expression of type "Mapped[List[C]]" # noqa @@ -47,7 +47,8 @@ class A: b1 = B(ordering=10) # in this case, the plugin infers OrderingList as the type. not great -a1 = A(bs=OrderingList(b1)) +a1 = A() +a1.bs.append(b1) # so we want to support being able to override it at least a2 = A(bs_w_list=[b1])