From: Mike Bayer Date: Thu, 30 Mar 2023 16:55:45 +0000 (-0400) Subject: copy deferred attributes for mapped_column X-Git-Tag: rel_2_0_8~4^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=671e0197b600b7b418fe7ca08d8864ea90f9a4f5;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git 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 --- diff --git a/doc/build/changelog/unreleased_20/9550.rst b/doc/build/changelog/unreleased_20/9550.rst new file mode 100644 index 0000000000..f8826727fb --- /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 4c07bad235..2f7b85d88f 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 cd6b86e5fd..d63c016796 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 98c496a81f..3e34b11d38 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)