From: Pascal Corpet Date: Thu, 28 Sep 2023 18:08:23 +0000 (-0400) Subject: handle builtins types in annotations with __allow_unmapped__ X-Git-Tag: rel_2_0_22~22^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=37b1303d94f47d76f7e5ab3dbcc705161a93d6e7;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git handle builtins types in annotations with __allow_unmapped__ 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 --- diff --git a/doc/build/changelog/unreleased_20/10385.rst b/doc/build/changelog/unreleased_20/10385.rst new file mode 100644 index 0000000000..9cc47d28ee --- /dev/null +++ b/doc/build/changelog/unreleased_20/10385.rst @@ -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. diff --git a/lib/sqlalchemy/util/typing.py b/lib/sqlalchemy/util/typing.py index 597549ce77..3d15d43db7 100644 --- a/lib/sqlalchemy/util/typing.py +++ b/lib/sqlalchemy/util/typing.py @@ -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 diff --git a/test/orm/declarative/test_tm_future_annotations_sync.py b/test/orm/declarative/test_tm_future_annotations_sync.py index 3790bd0440..03c758352f 100644 --- a/test/orm/declarative/test_tm_future_annotations_sync.py +++ b/test/orm/declarative/test_tm_future_annotations_sync.py @@ -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" diff --git a/test/orm/declarative/test_typed_mapping.py b/test/orm/declarative/test_typed_mapping.py index 7ddf2da7f8..4202166fbc 100644 --- a/test/orm/declarative/test_typed_mapping.py +++ b/test/orm/declarative/test_typed_mapping.py @@ -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"