[Sqlalchemy-tickets] Issue #4124: AbstractConcreteBase transmitting inappropriate "load only" props
Brought to you by:
zzzeek
From: Michael B. <iss...@bi...> - 2017-10-28 16:27:34
|
New issue 4124: AbstractConcreteBase transmitting inappropriate "load only" props to expired relationship item https://bitbucket.org/zzzeek/sqlalchemy/issues/4124/abstractconcretebase-transmitting Michael Bayer: ``` #!python from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import AbstractConcreteBase Base = declarative_base() class Abstract(AbstractConcreteBase, Base): pass # using this base, no problem # class Abstract(Base): # __abstract__ = True class Concrete(Abstract): __tablename__ = 'concrete' id = Column(Integer, primary_key=True) details = relationship("Detail") class Detail(Base): __tablename__ = 'detail' id = Column(Integer, primary_key=True) c2id = Column(ForeignKey('concrete.id')) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) s = Session(e) s.add(Concrete(details=[Detail()])) s.commit() c1 = s.query(Concrete).first() # triggers bug s.expire(c1) c1.details ``` trace, illustrates the pseudocolumn "type" is involved, also any other columns that get transmitted up to the base from other sibling classes end up here as well ``` #! Traceback (most recent call last): File "test.py", line 44, in <module> c1.details File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 242, in __get__ return self.impl.get(instance_state(instance), dict_) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 603, in get value = self.callable_(state, passive) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/strategies.py", line 623, in _load_for_state return self._emit_lazyload(session, state, ident_key, passive) File "<string>", line 1, in <lambda> File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/strategies.py", line 733, in _emit_lazyload lazy_clause, params = self._generate_lazy_clause(state, passive) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/strategies.py", line 556, in _generate_lazy_clause state, dict_, ident, passive) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/mapper.py", line 2609, in _get_state_attr_by_column return state.manager[prop.key].impl.get(state, dict_, passive=passive) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 598, in get value = state._load_expired(state, passive) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/state.py", line 594, in _load_expired self.manager.deferred_scalar_loader(self, toload) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/loading.py", line 835, in load_scalar_attributes only_load_props=attribute_names) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/loading.py", line 231, in load_on_ident return q.one() File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/query.py", line 2835, in one ret = self.one_or_none() File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/query.py", line 2805, in one_or_none ret = list(self) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/loading.py", line 97, in instances util.raise_from_cause(err) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/util/compat.py", line 203, in raise_from_cause reraise(type(exception), exception, tb=exc_tb, cause=cause) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/loading.py", line 60, in instances for query_entity in query._entities File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/query.py", line 3720, in row_processor polymorphic_discriminator=self._polymorphic_discriminator File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/loading.py", line 307, in _instance_processor mapper._props[k] for k in only_load_props) File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/loading.py", line 307, in <genexpr> mapper._props[k] for k in only_load_props) KeyError: 'type' ``` |