From: Mike Bayer Date: Mon, 10 Apr 2023 14:28:44 +0000 (-0400) Subject: include declared_directive as a declared_attr X-Git-Tag: rel_2_0_10~23^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bf51ff3248d1c87cbc7a846e2e6886339d59b9cb;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git include declared_directive as a declared_attr Fixed issue where the :meth:`_orm.declared_attr.directive` modifier was not correctly honored for subclasses when applied to the ``__mapper_args__`` special method name, as opposed to direct use of :class:`_orm.declared_attr`. The two constructs should have identical runtime behaviors. Fixes: #9625 Change-Id: I0dfe9e73bb45f70dbebc8e94ce280ad3b52e867f --- diff --git a/doc/build/changelog/unreleased_20/9625.rst b/doc/build/changelog/unreleased_20/9625.rst new file mode 100644 index 0000000000..edb4c0aa77 --- /dev/null +++ b/doc/build/changelog/unreleased_20/9625.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, orm + :tickets: 9625 + + Fixed issue where the :meth:`_orm.declared_attr.directive` modifier was not + correctly honored for subclasses when applied to the ``__mapper_args__`` + special method name, as opposed to direct use of + :class:`_orm.declared_attr`. The two constructs should have identical + runtime behaviors. diff --git a/lib/sqlalchemy/orm/decl_base.py b/lib/sqlalchemy/orm/decl_base.py index bd62c3c1b4..beede0ddbc 100644 --- a/lib/sqlalchemy/orm/decl_base.py +++ b/lib/sqlalchemy/orm/decl_base.py @@ -260,9 +260,9 @@ def _mapper( @util.preload_module("sqlalchemy.orm.decl_api") def _is_declarative_props(obj: Any) -> bool: - declared_attr = util.preloaded.orm_decl_api.declared_attr + _declared_attr_common = util.preloaded.orm_decl_api._declared_attr_common - return isinstance(obj, (declared_attr, util.classproperty)) + return isinstance(obj, (_declared_attr_common, util.classproperty)) def _check_declared_props_nocascade( diff --git a/test/orm/declarative/test_inheritance.py b/test/orm/declarative/test_inheritance.py index 4cc086be22..e8658926bc 100644 --- a/test/orm/declarative/test_inheritance.py +++ b/test/orm/declarative/test_inheritance.py @@ -68,6 +68,47 @@ class DeclarativeInheritanceTest( assert class_mapper(Engineer).polymorphic_identity is None assert class_mapper(Engineer).polymorphic_on is Person.__table__.c.type + @testing.variation("directive", ["declared_attr", "da_directive"]) + def test_declared_attr_mapped_args(self, directive): + class Employee(Base): + __tablename__ = "employee" + + id: Mapped[int] = mapped_column(primary_key=True) + type: Mapped[str] = mapped_column(String(50)) + + if directive.declared_attr: + + @declared_attr + def __mapper_args__(cls): + if cls.__name__ == "Employee": + return { + "polymorphic_on": cls.type, + "polymorphic_identity": "Employee", + } + else: + return {"polymorphic_identity": cls.__name__} + + elif directive.da_directive: + + @declared_attr.directive + def __mapper_args__(cls): + if cls.__name__ == "Employee": + return { + "polymorphic_on": cls.type, + "polymorphic_identity": "Employee", + } + else: + return {"polymorphic_identity": cls.__name__} + + else: + directive.fail() + + class Engineer(Employee): + pass + + eq_(class_mapper(Engineer).polymorphic_identity, "Engineer") + eq_(class_mapper(Employee).polymorphic_identity, "Employee") + def test_we_must_only_copy_column_mapper_args(self): class Person(Base):