]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
improve return type for QueryableAttribute.and_()
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 18 Apr 2023 13:42:50 +0000 (09:42 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 18 Apr 2023 15:20:47 +0000 (11:20 -0400)
Fixed typing issue where :meth:`_orm.PropComparator.and_` expressions would
not be correctly typed inside of loader options such as
:func:`_orm.selectinload`.

Fixes: #9669
Change-Id: I874cb22c004e0a24f2b7f530fda542de2c4c6d3b

doc/build/changelog/unreleased_20/9669.rst [new file with mode: 0644]
lib/sqlalchemy/orm/attributes.py
test/ext/mypy/plain_files/orm_querying.py [new file with mode: 0644]

diff --git a/doc/build/changelog/unreleased_20/9669.rst b/doc/build/changelog/unreleased_20/9669.rst
new file mode 100644 (file)
index 0000000..1ab9b07
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: bug, typing
+    :tickets: 9669
+
+    Fixed typing issue where :meth:`_orm.PropComparator.and_` expressions would
+    not be correctly typed inside of loader options such as
+    :func:`_orm.selectinload`.
index 3a60eda4f298d4b59fb1adf62ab2dc7bb8f6817c..69ddd33889b0f071eccbc691391ffe47e74ddeaf 100644 (file)
@@ -405,7 +405,7 @@ class QueryableAttribute(
 
     def and_(
         self, *clauses: _ColumnExpressionArgument[bool]
-    ) -> interfaces.PropComparator[bool]:
+    ) -> QueryableAttribute[bool]:
         if TYPE_CHECKING:
             assert isinstance(self.comparator, RelationshipProperty.Comparator)
 
diff --git a/test/ext/mypy/plain_files/orm_querying.py b/test/ext/mypy/plain_files/orm_querying.py
new file mode 100644 (file)
index 0000000..6bde850
--- /dev/null
@@ -0,0 +1,38 @@
+from __future__ import annotations
+
+from sqlalchemy import ForeignKey
+from sqlalchemy import select
+from sqlalchemy.orm import aliased
+from sqlalchemy.orm import DeclarativeBase
+from sqlalchemy.orm import Mapped
+from sqlalchemy.orm import mapped_column
+from sqlalchemy.orm import relationship
+from sqlalchemy.orm import selectinload
+
+
+class Base(DeclarativeBase):
+    pass
+
+
+class A(Base):
+    __tablename__ = "a"
+
+    id: Mapped[int] = mapped_column(primary_key=True)
+    data: Mapped[str]
+    bs: Mapped[list[B]] = relationship("B")
+
+
+class B(Base):
+    __tablename__ = "b"
+    id: Mapped[int] = mapped_column(primary_key=True)
+    a_id: Mapped[int] = mapped_column(ForeignKey("a.id"))
+    data: Mapped[str]
+
+
+def test_9669_and() -> None:
+    select(A).options(selectinload(A.bs.and_(B.data == "some data")))
+
+
+def test_9669_of_type() -> None:
+    ba = aliased(B)
+    select(A).options(selectinload(A.bs.of_type(ba)))