--- /dev/null
+.. 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.
@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(
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):