From: Mike Bayer Date: Thu, 12 Jun 2008 03:34:13 +0000 (+0000) Subject: - the enable_typechecks=False setting on relation() X-Git-Tag: rel_0_4_7~20 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ff364b9c54715be82180c62bf9d5db0ea4b047e3;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - 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. --- diff --git a/CHANGES b/CHANGES index ec85febbb5..7f9d208b9e 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,12 @@ CHANGES - 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 diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index c667460a71..c16bd8bbd0 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -108,11 +108,12 @@ class DependencyProcessor(object): 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 diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 448d797d06..d39e743e01 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -945,9 +945,9 @@ class Mapper(object): 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_ diff --git a/test/orm/relationships.py b/test/orm/relationships.py index 40773f8359..de3028903e 100644 --- a/test/orm/relationships.py +++ b/test/orm/relationships.py @@ -646,11 +646,8 @@ class TypeMatchTest(ORMTest): 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 @@ -668,11 +665,7 @@ class TypeMatchTest(ORMTest): 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 @@ -687,11 +680,8 @@ class TypeMatchTest(ORMTest): 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 @@ -703,6 +693,7 @@ class TypeMatchTest(ORMTest): d1 = D() d1.a = b1 sess = create_session() + try: sess.save(d1) assert False