diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2017-10-28 13:28:58 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2017-10-28 13:29:48 -0400 |
| commit | fd4289c5829d6498495ac59fe1dccb23b4975281 (patch) | |
| tree | 23881bd839a6ca99d62748ef910fc1c343c5284c /test/ext | |
| parent | f7b957b589207cae98b6feec63be84ee6423c3ca (diff) | |
| download | sqlalchemy-fd4289c5829d6498495ac59fe1dccb23b4975281.tar.gz | |
Filter attributes we don't map during a load_scalar_attributes
Fixed bug where a descriptor that is elsewhere a mapped column
or relationship within a hierarchy based on :class:`.AbstractConcreteBase`
would be referred towards during a refresh operation, causing an error
as the attribute is not mapped as a mapper property.
A similar issue can arise for other attributes like the "type" column
added by :class:`.AbstractConcreteBase` if the class fails to include
"concrete=True" in its mapper, however the check here should also
prevent that scenario from causing a problem.
Change-Id: I407b07a3a3e2c374da19fc86ed44b987d595dcfa
Fixes: #4124
Diffstat (limited to 'test/ext')
| -rw-r--r-- | test/ext/declarative/test_inheritance.py | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/test/ext/declarative/test_inheritance.py b/test/ext/declarative/test_inheritance.py index e57320cfe..7ced8ec15 100644 --- a/test/ext/declarative/test_inheritance.py +++ b/test/ext/declarative/test_inheritance.py @@ -1092,6 +1092,10 @@ class ConcreteInhTest(_RemoveListeners, DeclarativeTestBase): eq_(sess.query(Manager).all(), [Manager(name='dogbert')]) eq_(sess.query(Boss).all(), [Boss(name='pointy haired')]) + e1 = sess.query(Engineer).order_by(Engineer.name).first() + sess.expire(e1) + eq_(e1.name, 'dilbert') + def test_explicit(self): engineers = Table( 'engineers', Base.metadata, @@ -1213,6 +1217,55 @@ class ConcreteInhTest(_RemoveListeners, DeclarativeTestBase): self._roundtrip(Employee, Manager, Engineer, Boss) + def test_abstract_concrete_extension_descriptor_refresh(self): + class Employee(AbstractConcreteBase, Base, fixtures.ComparableEntity): + @declared_attr + def name(cls): + return Column(String(50)) + + class Manager(Employee): + __tablename__ = 'manager' + employee_id = Column(Integer, primary_key=True, + test_needs_autoincrement=True) + paperwork = Column(String(10)) + __mapper_args__ = { + 'polymorphic_identity': 'manager', 'concrete': True} + + class Engineer(Employee): + __tablename__ = 'engineer' + employee_id = Column(Integer, primary_key=True, + test_needs_autoincrement=True) + + @property + def paperwork(self): + return "p" + + __mapper_args__ = { + 'polymorphic_identity': 'engineer', 'concrete': True} + + Base.metadata.create_all() + sess = Session() + sess.add(Engineer(name='d')) + sess.commit() + + # paperwork is excluded because there's a descritor; so it is + # not in the Engineers mapped properties at all, though is inside the + # class manager. Maybe it shouldn't be in the class manager either. + assert 'paperwork' in Engineer.__mapper__.class_manager + assert 'paperwork' not in Engineer.__mapper__.attrs.keys() + + # type currently does get mapped, as a + # ConcreteInheritedProperty, which means, "ignore this thing inherited + # from the concrete base". if we didn't specify concrete=True, then + # this one gets stuck in the error condition also. + assert 'type' in Engineer.__mapper__.class_manager + assert 'type' in Engineer.__mapper__.attrs.keys() + + e1 = sess.query(Engineer).first() + eq_(e1.name, 'd') + sess.expire(e1) + eq_(e1.name, 'd') + def test_concrete_extension(self): class Employee(ConcreteBase, Base, fixtures.ComparableEntity): __tablename__ = 'employee' |
