--- /dev/null
+.. change::
+ :tags: bug, orm
+ :tickets: 10516
+
+ Fixed issue where the ``__allow_unmapped__`` directive failed to allow for
+ legacy :class:`.Column` / :func:`.deferred` mappings that nonetheless had
+ annotations such as ``Any`` or a specific type without ``Mapped[]`` as
+ their type, without errors related to locating the attribute name.
cls, "_sa_decl_prepare_nocascade", strict=True
)
+ allow_unmapped_annotations = self.allow_unmapped_annotations
expect_annotations_wo_mapped = (
- self.allow_unmapped_annotations
- or self.is_dataclass_prior_to_mapping
+ allow_unmapped_annotations or self.is_dataclass_prior_to_mapping
)
look_for_dataclass_things = bool(self.dataclass_setup_arguments)
# Mapped[] etc. were not used. If annotation is None,
# do declarative_scan so that the property can raise
# for required
- if mapped_container is not None or annotation is None:
+ if (
+ mapped_container is not None
+ or annotation is None
+ # issue #10516: need to do declarative_scan even with
+ # a non-Mapped annotation if we are doing
+ # __allow_unmapped__, for things like col.name
+ # assignment
+ or allow_unmapped_annotations
+ ):
try:
value.declarative_scan(
self,
status: int
+ @testing.variation("annotation", ["none", "any", "datatype"])
+ @testing.variation("explicit_name", [True, False])
+ @testing.variation("attribute", ["column", "deferred"])
+ def test_allow_unmapped_cols(self, annotation, explicit_name, attribute):
+ class Base(DeclarativeBase):
+ __allow_unmapped__ = True
+
+ if attribute.column:
+ if explicit_name:
+ attr = Column("data_one", Integer)
+ else:
+ attr = Column(Integer)
+ elif attribute.deferred:
+ if explicit_name:
+ attr = deferred(Column("data_one", Integer))
+ else:
+ attr = deferred(Column(Integer))
+ else:
+ attribute.fail()
+
+ class MyClass(Base):
+ __tablename__ = "mytable"
+
+ id: Mapped[int] = mapped_column(primary_key=True)
+
+ if annotation.none:
+ data = attr
+ elif annotation.any:
+ data: Any = attr
+ elif annotation.datatype:
+ data: int = attr
+ else:
+ annotation.fail()
+
+ if explicit_name:
+ eq_(MyClass.__table__.c.keys(), ["id", "data_one"])
+ else:
+ eq_(MyClass.__table__.c.keys(), ["id", "data"])
+
def test_column_default(self, decl_base):
class MyClass(decl_base):
__tablename__ = "mytable"
status: int
+ @testing.variation("annotation", ["none", "any", "datatype"])
+ @testing.variation("explicit_name", [True, False])
+ @testing.variation("attribute", ["column", "deferred"])
+ def test_allow_unmapped_cols(self, annotation, explicit_name, attribute):
+ class Base(DeclarativeBase):
+ __allow_unmapped__ = True
+
+ if attribute.column:
+ if explicit_name:
+ attr = Column("data_one", Integer)
+ else:
+ attr = Column(Integer)
+ elif attribute.deferred:
+ if explicit_name:
+ attr = deferred(Column("data_one", Integer))
+ else:
+ attr = deferred(Column(Integer))
+ else:
+ attribute.fail()
+
+ class MyClass(Base):
+ __tablename__ = "mytable"
+
+ id: Mapped[int] = mapped_column(primary_key=True)
+
+ if annotation.none:
+ data = attr
+ elif annotation.any:
+ data: Any = attr
+ elif annotation.datatype:
+ data: int = attr
+ else:
+ annotation.fail()
+
+ if explicit_name:
+ eq_(MyClass.__table__.c.keys(), ["id", "data_one"])
+ else:
+ eq_(MyClass.__table__.c.keys(), ["id", "data"])
+
def test_column_default(self, decl_base):
class MyClass(decl_base):
__tablename__ = "mytable"