]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
copy deferred attributes for mapped_column
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 30 Mar 2023 16:55:45 +0000 (12:55 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 30 Mar 2023 19:15:19 +0000 (15:15 -0400)
Fixed issue where the :func:`_orm.mapped_column` construct would raise an
internal error if used on a Declarative mixin and included the
:paramref:`_orm.mapped_column.deferred` parameter.

Fixes: #9550
Change-Id: I0cc5ec4910656abc9a3fb7b7b60880256cd7c61e

doc/build/changelog/unreleased_20/9550.rst [new file with mode: 0644]
lib/sqlalchemy/orm/properties.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/9550.rst b/doc/build/changelog/unreleased_20/9550.rst
new file mode 100644 (file)
index 0000000..f882672
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: bug, orm
+    :tickets: 9550
+
+    Fixed issue where the :func:`_orm.mapped_column` construct would raise an
+    internal error if used on a Declarative mixin and included the
+    :paramref:`_orm.mapped_column.deferred` parameter.
index 4c07bad235f6aabc9c75456835635a7a99934165..2f7b85d88fc13e69de2fb862f920200730a85f04 100644 (file)
@@ -594,6 +594,8 @@ class MappedColumn(
         new = self.__class__.__new__(self.__class__)
         new.column = self.column._copy(**kw)
         new.deferred = self.deferred
+        new.deferred_group = self.deferred_group
+        new.deferred_raiseload = self.deferred_raiseload
         new.foreign_keys = new.column.foreign_keys
         new._has_nullable = self._has_nullable
         new._attribute_options = self._attribute_options
index cd6b86e5fd611cd0db4ddfcc5f815840ea80b791..d63c016796ef2dc3b70362ea9d1f614d26004c66 100644 (file)
@@ -22,6 +22,7 @@ from typing import NewType
 from typing import Optional
 from typing import Set
 from typing import Type
+from typing import TYPE_CHECKING
 from typing import TypeVar
 from typing import Union
 import uuid
@@ -453,8 +454,9 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL):
         is_(User.__table__.c.data.type.__class__, Integer)
 
     @testing.combinations(True, False, argnames="include_rhs_type")
+    @testing.combinations(True, False, argnames="use_mixin")
     def test_construct_nullability_overrides(
-        self, decl_base, include_rhs_type
+        self, decl_base, include_rhs_type, use_mixin
     ):
 
         if include_rhs_type:
@@ -487,10 +489,22 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL):
             }
         )
 
-        class User(decl_base):
-            __tablename__ = "users"
+        if TYPE_CHECKING:
 
-            id: Mapped[int] = mapped_column(primary_key=True)
+            class user_base:
+                pass
+
+        else:
+            if use_mixin:
+                user_base = object
+            else:
+                user_base = decl_base
+
+        class UserPossibleMixin(user_base):
+            if not use_mixin:
+                __tablename__ = "users"
+
+                id: Mapped[int] = mapped_column(primary_key=True)  # noqa: A001
 
             lnnl_rndf: Mapped[str] = mapped_column(*args)
             lnnl_rnnl: Mapped[str] = mapped_column(*args, nullable=False)
@@ -506,6 +520,10 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL):
             # test #9177 cases
             anno_1a: Mapped[anno_str] = mapped_column(*args)
             anno_1b: Mapped[anno_str] = mapped_column(*args, nullable=True)
+            anno_1c: Mapped[anno_str] = mapped_column(*args, deferred=True)
+            anno_1d: Mapped[anno_str] = mapped_column(
+                *args, deferred=True, deferred_group="mygroup"
+            )
 
             anno_2a: Mapped[anno_str_optional] = mapped_column(*args)
             anno_2b: Mapped[anno_str_optional] = mapped_column(
@@ -538,6 +556,20 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL):
                 *args, nullable=True
             )
 
+        if use_mixin:
+
+            class User(UserPossibleMixin, decl_base):
+                __tablename__ = "users"
+
+                id: Mapped[int] = mapped_column(primary_key=True)
+
+        else:
+            User = UserPossibleMixin
+
+        eq_(User.anno_1b.property.deferred, False)
+        eq_(User.anno_1c.property.deferred, True)
+        eq_(User.anno_1d.property.group, "mygroup")
+
         is_false(User.__table__.c.lnnl_rndf.nullable)
         is_false(User.__table__.c.lnnl_rnnl.nullable)
         is_true(User.__table__.c.lnnl_rnl.nullable)
index 98c496a81f979fd3134769f73d59440e63c85639..3e34b11d38ac1ad7317a7273a63889be55fd7fba 100644 (file)
@@ -13,6 +13,7 @@ from typing import NewType
 from typing import Optional
 from typing import Set
 from typing import Type
+from typing import TYPE_CHECKING
 from typing import TypeVar
 from typing import Union
 import uuid
@@ -444,8 +445,9 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL):
         is_(User.__table__.c.data.type.__class__, Integer)
 
     @testing.combinations(True, False, argnames="include_rhs_type")
+    @testing.combinations(True, False, argnames="use_mixin")
     def test_construct_nullability_overrides(
-        self, decl_base, include_rhs_type
+        self, decl_base, include_rhs_type, use_mixin
     ):
 
         if include_rhs_type:
@@ -478,10 +480,22 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL):
             }
         )
 
-        class User(decl_base):
-            __tablename__ = "users"
+        if TYPE_CHECKING:
 
-            id: Mapped[int] = mapped_column(primary_key=True)
+            class user_base:
+                pass
+
+        else:
+            if use_mixin:
+                user_base = object
+            else:
+                user_base = decl_base
+
+        class UserPossibleMixin(user_base):
+            if not use_mixin:
+                __tablename__ = "users"
+
+                id: Mapped[int] = mapped_column(primary_key=True)  # noqa: A001
 
             lnnl_rndf: Mapped[str] = mapped_column(*args)
             lnnl_rnnl: Mapped[str] = mapped_column(*args, nullable=False)
@@ -497,6 +511,10 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL):
             # test #9177 cases
             anno_1a: Mapped[anno_str] = mapped_column(*args)
             anno_1b: Mapped[anno_str] = mapped_column(*args, nullable=True)
+            anno_1c: Mapped[anno_str] = mapped_column(*args, deferred=True)
+            anno_1d: Mapped[anno_str] = mapped_column(
+                *args, deferred=True, deferred_group="mygroup"
+            )
 
             anno_2a: Mapped[anno_str_optional] = mapped_column(*args)
             anno_2b: Mapped[anno_str_optional] = mapped_column(
@@ -529,6 +547,20 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL):
                 *args, nullable=True
             )
 
+        if use_mixin:
+
+            class User(UserPossibleMixin, decl_base):
+                __tablename__ = "users"
+
+                id: Mapped[int] = mapped_column(primary_key=True)
+
+        else:
+            User = UserPossibleMixin
+
+        eq_(User.anno_1b.property.deferred, False)
+        eq_(User.anno_1c.property.deferred, True)
+        eq_(User.anno_1d.property.group, "mygroup")
+
         is_false(User.__table__.c.lnnl_rndf.nullable)
         is_false(User.__table__.c.lnnl_rnnl.nullable)
         is_true(User.__table__.c.lnnl_rnl.nullable)