]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Fix OrderingList handling
authorBryan Forbes <bryan@reigndropsfall.net>
Mon, 12 Apr 2021 21:24:37 +0000 (16:24 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 13 Apr 2021 19:40:34 +0000 (15:40 -0400)
Revised the fix for ``OrderingList`` from version 1.4.7 which was testing
against the incorrect API.

Fixes: #6205
Change-Id: I1d3f8b6534b70ae000294c2a67f08117cb77ee99

doc/build/changelog/unreleased_14/6205.rst [new file with mode: 0644]
lib/sqlalchemy/ext/mypy/infer.py
setup.cfg
test/ext/mypy/files/orderinglist1.py
test/ext/mypy/files/orderinglist2.py

diff --git a/doc/build/changelog/unreleased_14/6205.rst b/doc/build/changelog/unreleased_14/6205.rst
new file mode 100644 (file)
index 0000000..8a901bb
--- /dev/null
@@ -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.
index 7915c3ae2dcdabbd7a2486b438e0ea44d2e61cf0..d734d588e53fd7d68e165ce2ff67eec54e0a61cf 100644 (file)
@@ -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,
index b0eebb2855cc157f047ade93c1059a62d40ad996..001a38e30ffecc2dc7dce41848be529c0a7b4d11 100644 (file)
--- 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
index cb06ba492fabeae89a07e1edf8e6f2e4d7c873c9..661d55a7b6a8acdb29a601a3b7114c385e6ad7d2 100644 (file)
@@ -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[<python type>] 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)
 
index 2a1623e5c8711dbcebcab24288ef0c6355702bd5..eb50c5391bef9952dfd32975be3bcde425439619 100644 (file)
@@ -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])