now only allows subtypes with inheriting mappers.
Totally unrelated types, or subtypes not set up with
mapper inheritance against the target mapper are
still not allowed.
- Query.count() will take single-table inheritance
subtypes into account the same way row-based
results do. [ticket:1008]
+
+ - the enable_typechecks=False setting on relation()
+ now only allows subtypes with inheriting mappers.
+ Totally unrelated types, or subtypes not set up with
+ mapper inheritance against the target mapper are
+ still not allowed.
- mysql
- Added 'CALL' to the list of SQL keywords which return
raise NotImplementedError()
def _verify_canload(self, state):
- if not self.enable_typechecks:
- return
- if state is not None and not self.mapper._canload(state):
- raise exceptions.FlushError("Attempting to flush an item of type %s on collection '%s', which is handled by mapper '%s' and does not load items of that type. Did you mean to use a polymorphic mapper for this relationship ? Set 'enable_typechecks=False' on the relation() to disable this exception. Mismatched typeloading may cause bi-directional relationships (backrefs) to not function properly." % (state.class_, self.prop, self.mapper))
-
+ if state is not None and not self.mapper._canload(state, allow_subtypes=not self.enable_typechecks):
+ if self.mapper._canload(state, allow_subtypes=True):
+ raise exceptions.FlushError("Attempting to flush an item of type %s on collection '%s', which is not the expected type %s. Configure mapper '%s' to load this subtype polymorphically, or set enable_typechecks=False to allow subtypes. Mismatched typeloading may cause bi-directional relationships (backrefs) to not function properly." % (state.class_, self.prop, self.mapper.class_, self.mapper))
+ else:
+ raise exceptions.FlushError("Attempting to flush an item of type %s on collection '%s', whose mapper does not inherit from that of %s." % (state.class_, self.prop, self.mapper.class_))
+
def _synchronize(self, state, child, associationrow, clearkeys, uowcommit):
"""Called during a flush to synchronize primary key identifier
values between a parent/child object, as well as to an
def _primary_key_from_state(self, state):
return [self._get_state_attr_by_column(state, column) for column in self.primary_key]
- def _canload(self, state):
- if self.polymorphic_on:
- return issubclass(state.class_, self.class_)
+ def _canload(self, state, allow_subtypes):
+ if self.polymorphic_on or allow_subtypes:
+ return self.isa(_state_mapper(state))
else:
return state.class_ is self.class_
sess.save(a1)
sess.save(b1)
sess.save(c1)
- try:
- sess.flush()
- assert False
- except exceptions.FlushError, err:
- assert str(err).startswith("Attempting to flush an item of type %s on collection 'A.bs (B)', which is handled by mapper 'Mapper|B|b' and does not load items of that type. Did you mean to use a polymorphic mapper for this relationship ?" % C)
+ self.assertRaises(exceptions.FlushError, sess.flush)
+
def test_o2m_nopoly_onflush(self):
class A(object):pass
class B(object):pass
sess.save(a1)
sess.save(b1)
sess.save(c1)
- try:
- sess.flush()
- assert False
- except exceptions.FlushError, err:
- assert str(err).startswith("Attempting to flush an item of type %s on collection 'A.bs (B)', which is handled by mapper 'Mapper|B|b' and does not load items of that type. Did you mean to use a polymorphic mapper for this relationship ?" % C)
+ self.assertRaises(exceptions.FlushError, sess.flush)
def test_m2o_nopoly_onflush(self):
class A(object):pass
sess = create_session()
sess.save(b1)
sess.save(d1)
- try:
- sess.flush()
- assert False
- except exceptions.FlushError, err:
- assert str(err).startswith("Attempting to flush an item of type %s on collection 'D.a (A)', which is handled by mapper 'Mapper|A|a' and does not load items of that type. Did you mean to use a polymorphic mapper for this relationship ?" % B)
+ self.assertRaises(exceptions.FlushError, sess.flush)
+
def test_m2o_oncascade(self):
class A(object):pass
class B(object):pass
d1 = D()
d1.a = b1
sess = create_session()
+
try:
sess.save(d1)
assert False