]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
handle builtins types in annotations with __allow_unmapped__
authorPascal Corpet <pascal@co2ai.com>
Thu, 28 Sep 2023 18:08:23 +0000 (14:08 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 29 Sep 2023 15:00:48 +0000 (11:00 -0400)
Fixed issue with ``__allow_unmapped__`` declarative option where types that
were declared using collection types such as ``list[SomeClass]`` vs. the
typing construct ``List[SomeClass]`` would fail to be recognized correctly.
Pull request courtesy Pascal Corpet.

Fixes: #10385
Closes: #10390
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/10390
Pull-request-sha: f8796965aefc1852d4b1137d04bf811072a1a0e9

Change-Id: I114d29c3c076386508300e979371b0d760b761c7

doc/build/changelog/unreleased_20/10385.rst [new file with mode: 0644]
lib/sqlalchemy/util/typing.py
test/orm/declarative/test_tm_future_annotations_sync.py
test/orm/declarative/test_typed_mapping.py

diff --git a/doc/build/changelog/unreleased_20/10385.rst b/doc/build/changelog/unreleased_20/10385.rst
new file mode 100644 (file)
index 0000000..9cc47d2
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: orm, bug
+    :tickets: 10385
+
+    Fixed issue with ``__allow_unmapped__`` declarative option
+    where types that were declared using collection types such as
+    ``list[SomeClass]`` vs. the typing construct ``List[SomeClass]``
+    would fail to be recognized correctly.  Pull request courtesy
+    Pascal Corpet.
index 597549ce77d390df40d5957dbaf2122bd9b337a9..3d15d43db7652212d78994c51e2975ae0b987cee 100644 (file)
@@ -8,6 +8,7 @@
 
 from __future__ import annotations
 
+import builtins
 import re
 import sys
 import typing
@@ -249,6 +250,12 @@ def eval_name_only(
     try:
         return base_globals[name]
     except KeyError as ke:
+        # check in builtins as well to handle `list`, `set` or `dict`, etc.
+        try:
+            return builtins.__dict__[name]
+        except KeyError:
+            pass
+
         raise NameError(
             f"Could not locate name {name} in module {module_name}"
         ) from ke
index 3790bd0440cd29209d5ad5e3db65bdd7f8ecc3f4..03c758352f2209beb8c391288d0764d16164e85f 100644 (file)
@@ -2411,8 +2411,17 @@ class RelationshipLHSTest(fixtures.TestBase, testing.AssertsCompiledSQL):
 
                 decl_base.registry.configure()
 
-    def test_14_style_anno_accepted_w_allow_unmapped(self):
-        """test for #8692"""
+    @testing.variation(
+        "collection_type",
+        [
+            ("list", testing.requires.python310),
+            "List",
+            ("set", testing.requires.python310),
+            "Set",
+        ],
+    )
+    def test_14_style_anno_accepted_w_allow_unmapped(self, collection_type):
+        """test for #8692 and #10385"""
 
         class Base(DeclarativeBase):
             __allow_unmapped__ = True
@@ -2422,7 +2431,29 @@ class RelationshipLHSTest(fixtures.TestBase, testing.AssertsCompiledSQL):
 
             id: Mapped[int] = mapped_column(primary_key=True)
             data: str = Column(String)
-            bs: List["B"] = relationship("B", back_populates="a")  # noqa: F821
+
+            if collection_type.list:
+                bs: list["B"] = relationship(  # noqa: F821
+                    "B",
+                    back_populates="a",
+                )
+            elif collection_type.List:
+                bs: List["B"] = relationship(  # noqa: F821
+                    "B",
+                    back_populates="a",
+                )
+            elif collection_type.set:
+                bs: set["B"] = relationship(  # noqa: F821
+                    "B",
+                    back_populates="a",
+                )
+            elif collection_type.Set:
+                bs: Set["B"] = relationship(  # noqa: F821
+                    "B",
+                    back_populates="a",
+                )
+            else:
+                collection_type.fail()
 
         class B(Base):
             __tablename__ = "b"
index 7ddf2da7f883bb420b072917743caf77b86608e6..4202166fbc0e16799efd40437b80ec2a7bea0d1f 100644 (file)
@@ -2402,8 +2402,17 @@ class RelationshipLHSTest(fixtures.TestBase, testing.AssertsCompiledSQL):
 
                 decl_base.registry.configure()
 
-    def test_14_style_anno_accepted_w_allow_unmapped(self):
-        """test for #8692"""
+    @testing.variation(
+        "collection_type",
+        [
+            ("list", testing.requires.python310),
+            "List",
+            ("set", testing.requires.python310),
+            "Set",
+        ],
+    )
+    def test_14_style_anno_accepted_w_allow_unmapped(self, collection_type):
+        """test for #8692 and #10385"""
 
         class Base(DeclarativeBase):
             __allow_unmapped__ = True
@@ -2413,7 +2422,29 @@ class RelationshipLHSTest(fixtures.TestBase, testing.AssertsCompiledSQL):
 
             id: Mapped[int] = mapped_column(primary_key=True)
             data: str = Column(String)
-            bs: List["B"] = relationship("B", back_populates="a")  # noqa: F821
+
+            if collection_type.list:
+                bs: list["B"] = relationship(  # noqa: F821
+                    "B",
+                    back_populates="a",
+                )
+            elif collection_type.List:
+                bs: List["B"] = relationship(  # noqa: F821
+                    "B",
+                    back_populates="a",
+                )
+            elif collection_type.set:
+                bs: set["B"] = relationship(  # noqa: F821
+                    "B",
+                    back_populates="a",
+                )
+            elif collection_type.Set:
+                bs: Set["B"] = relationship(  # noqa: F821
+                    "B",
+                    back_populates="a",
+                )
+            else:
+                collection_type.fail()
 
         class B(Base):
             __tablename__ = "b"