summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2023-03-30 12:55:45 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2023-03-30 15:15:19 -0400
commit671e0197b600b7b418fe7ca08d8864ea90f9a4f5 (patch)
tree8d1ebdad5aeac7d5080941b1741a7be9950e9c66
parent72d2ec57928bdf5649c551bdaa87b7fb0943c2fe (diff)
downloadsqlalchemy-671e0197b600b7b418fe7ca08d8864ea90f9a4f5.tar.gz
copy deferred attributes for mapped_column
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
-rw-r--r--doc/build/changelog/unreleased_20/9550.rst7
-rw-r--r--lib/sqlalchemy/orm/properties.py2
-rw-r--r--test/orm/declarative/test_tm_future_annotations_sync.py40
-rw-r--r--test/orm/declarative/test_typed_mapping.py40
4 files changed, 81 insertions, 8 deletions
diff --git a/doc/build/changelog/unreleased_20/9550.rst b/doc/build/changelog/unreleased_20/9550.rst
new file mode 100644
index 000000000..f8826727f
--- /dev/null
+++ b/doc/build/changelog/unreleased_20/9550.rst
@@ -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.
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 4c07bad23..2f7b85d88 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -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
diff --git a/test/orm/declarative/test_tm_future_annotations_sync.py b/test/orm/declarative/test_tm_future_annotations_sync.py
index cd6b86e5f..d63c01679 100644
--- a/test/orm/declarative/test_tm_future_annotations_sync.py
+++ b/test/orm/declarative/test_tm_future_annotations_sync.py
@@ -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)
diff --git a/test/orm/declarative/test_typed_mapping.py b/test/orm/declarative/test_typed_mapping.py
index 98c496a81..3e34b11d3 100644
--- a/test/orm/declarative/test_typed_mapping.py
+++ b/test/orm/declarative/test_typed_mapping.py
@@ -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)