]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- the enable_typechecks=False setting on relation()
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 12 Jun 2008 03:34:13 +0000 (03:34 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 12 Jun 2008 03:34:13 +0000 (03:34 +0000)
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.

CHANGES
lib/sqlalchemy/orm/dependency.py
lib/sqlalchemy/orm/mapper.py
test/orm/relationships.py

diff --git a/CHANGES b/CHANGES
index ec85febbb518506ef37379bdef337c8899bf321f..7f9d208b9e422f28561414ace494984af91cd004 100644 (file)
--- 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
index c667460a71796bece5c567ab23a36b95dc0e674c..c16bd8bbd00f5bec2aec8f49fcee0bbe3cbf793e 100644 (file)
@@ -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
index 448d797d06440bc8c2831703760c908253b31c85..d39e743e017f6c15b7c009b1fbbc680cc3f33564 100644 (file)
@@ -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_
 
index 40773f8359599013eaa697bf45996a146d257cea..de3028903eedda7ecc5ab985de9ffc449c0a91d4 100644 (file)
@@ -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