[Sqlalchemy-tickets] Issue #4286: mapper._subclass_load_via_in() returns mutable state (zzzeek/sqla
Brought to you by:
zzzeek
From: Michael B. <iss...@bi...> - 2018-06-25 02:09:39
|
New issue 4286: mapper._subclass_load_via_in() returns mutable state https://bitbucket.org/zzzeek/sqlalchemy/issues/4286/mapper_subclass_load_via_in-returns Michael Bayer: demo: ``` #!python from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declared_attr Base = declarative_base() class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) parent = relationship('Parent', backref=backref('children')) type = Column(String(), nullable=False) __mapper_args__ = { 'polymorphic_on': type, } class ChildSubclass1(Child): __tablename__ = 'child_subclass1' id = Column(Integer, ForeignKey('child.id'), primary_key=True) __mapper_args__ = { 'polymorphic_identity': 'subclass1', 'polymorphic_load': 'selectin' } class Other(Base): __tablename__ = 'other' id = Column(Integer, primary_key=True) child_subclass_id = Column(Integer, ForeignKey('child_subclass1.id')) child_subclass = relationship('ChildSubclass1', backref=backref('others')) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) def is_other_in_session(): return any(isinstance(model, Other) for model in session) session = Session(e, enable_baked_queries=False) parent = Parent() subclass1 = ChildSubclass1(parent=parent) other = Other(child_subclass=subclass1) session.add_all([parent, subclass1, other]) session.commit() # Test 1: Loading Parent + Children does not load Other print('\nTest #1: Loading Parent + Children does not load others') session.expunge_all() assert not is_other_in_session() parents = session.query(Parent).options( joinedload(Parent.children.of_type(ChildSubclass1))).all() assert not is_other_in_session() print('\nTest #2: Loading Parent + Children + Others loads others as expected') session.expunge_all() assert not is_other_in_session() parents = session.query(Parent).options( joinedload(Parent.children.of_type(ChildSubclass1)) .joinedload(ChildSubclass1.others) ).all() print('\nTest #3: Loading Parent + Children should not load others, ' 'but it does now') session.expunge_all() assert not is_other_in_session() parents = session.query(Parent).options( joinedload(Parent.children.of_type(ChildSubclass1)) ).all() assert not is_other_in_session(), 'The above query should not load any Others!' ``` the options being returned are fixed at _subclass_load_via_in and the options seem to be getting modified in place, test passes as: ``` #!diff diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index a30a8c243..17677cb3f 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -2814,7 +2814,8 @@ class Mapper(InspectionAttr): return q, enable_opt, disable_opt - @_memoized_configured_property + #@_memoized_configured_property + @property def _subclass_load_via_in_mapper(self): return self._subclass_load_via_in(self) ``` |