Commits

Mike Bayer committed 96ac631

- Fixed the error message emitted for "can't
execute syncrule for destination column 'q';
mapper 'X' does not map this column" to
reference the correct mapper. [ticket:2163].
- orm/test_sync.py covers orm/sync.py 100%

  • Participants
  • Parent commits d01350e
  • Branches rel_0_6

Comments (0)

Files changed (3)

     issues, the original rationale for the mutex.  
     [ticket:2148]
 
+  - Fixed the error message emitted for "can't
+    execute syncrule for destination column 'q';
+    mapper 'X' does not map this column" to 
+    reference the correct mapper.  [ticket:2163].
+
 - sql
   - Fixed bug whereby if FetchedValue was passed
     to column server_onupdate, it would not

lib/sqlalchemy/orm/sync.py

                                 "Can't execute sync rule for destination column '%s'; "
                                 "mapper '%s' does not map this column.  Try using an explicit"
                                 " `foreign_keys` collection which does not include this column "
-                                "(or use a viewonly=True relation)." % (dest_column, source_mapper)
+                                "(or use a viewonly=True relation)." % (dest_column, dest_mapper)
                                 )
     else:
         raise exc.UnmappedColumnError(

test/orm/test_sync.py

+from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message
+from sqlalchemy.test import testing
+from sqlalchemy.test.schema import Table, Column
+from sqlalchemy import Integer, String, ForeignKey, func
+from test.orm import _fixtures, _base
+from sqlalchemy.orm import mapper, relationship, backref, \
+                            create_session, unitofwork, attributes,\
+                            Session, class_mapper, sync, exc as orm_exc
+
+
+class AssertsUOW(object):
+    def _get_test_uow(self, session):
+        uow = unitofwork.UOWTransaction(session)
+        deleted = set(session._deleted)
+        new = set(session._new)
+        dirty = set(session._dirty_states).difference(deleted)
+        for s in new.union(dirty):
+            uow.register_object(s)
+        for d in deleted:
+            uow.register_object(d, isdelete=True)
+        return uow
+
+class SyncTest(_base.MappedTest, 
+                    testing.AssertsExecutionResults, AssertsUOW):
+
+    @classmethod
+    def define_tables(cls, metadata):
+        Table('t1', metadata,
+            Column('id', Integer, primary_key=True),
+            Column('foo', Integer)
+        )
+        Table('t2', metadata,
+            Column('id', Integer, ForeignKey('t1.id'), primary_key=True),
+            Column('t1id', Integer, ForeignKey('t1.id')),
+        )
+
+    @classmethod
+    def setup_classes(cls):
+        class A(_base.BasicEntity):
+            pass
+        class B(_base.BasicEntity):
+            pass
+
+    @classmethod
+    def setup_mappers(cls):
+        mapper(cls.classes.A, cls.tables.t1)
+        mapper(cls.classes.B, cls.tables.t2)
+
+    @testing.resolve_artifact_names
+    def _fixture(self):
+        A, B = self.classes.A, self.classes.B
+        session = create_session()
+        uowcommit = self._get_test_uow(session)
+        a_mapper = class_mapper(A)
+        b_mapper= class_mapper(B)
+        self.a1 = a1 = A()
+        self.b1 = b1 = B()
+        uowcommit = self._get_test_uow(session)
+        return uowcommit,\
+            attributes.instance_state(a1),\
+            attributes.instance_state(b1),\
+            a_mapper, b_mapper
+
+    def test_populate(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(a_mapper.c.id, b_mapper.c.id)]
+        a1.obj().id = 7
+        assert 'id' not in b1.obj().__dict__
+        sync.populate(a1, a_mapper, b1, b_mapper, pairs, uowcommit, False)
+        eq_(b1.obj().id, 7)
+        eq_(b1.obj().__dict__['id'], 7)
+        assert ("pk_cascaded", b1, b_mapper.c.id) not in uowcommit.attributes
+
+    def test_populate_flag_cascaded(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(a_mapper.c.id, b_mapper.c.id)]
+        a1.obj().id = 7
+        assert 'id' not in b1.obj().__dict__
+        sync.populate(a1, a_mapper, b1, b_mapper, pairs, uowcommit, True)
+        eq_(b1.obj().id, 7)
+        eq_(b1.obj().__dict__['id'], 7)
+        eq_(uowcommit.attributes[("pk_cascaded", b1, b_mapper.c.id)], True)
+
+    def test_populate_unmapped_source(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(b_mapper.c.id, b_mapper.c.id)]
+        assert_raises_message(
+            orm_exc.UnmappedColumnError,
+            "Can't execute sync rule for source column 't2.id'; "
+            r"mapper 'Mapper\|A\|t1' does not map this column.",
+            sync.populate,
+                a1, 
+                a_mapper, 
+                b1, 
+                b_mapper, 
+                pairs, 
+                uowcommit, False
+        )
+
+    def test_populate_unmapped_dest(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(a_mapper.c.id, a_mapper.c.id,)]
+        assert_raises_message(
+            orm_exc.UnmappedColumnError,
+            "Can't execute sync rule for destination "
+            r"column 't1.id'; mapper 'Mapper\|B\|t2' does not map this column.",
+            sync.populate,
+                a1, 
+                a_mapper, 
+                b1, 
+                b_mapper, 
+                pairs, 
+                uowcommit, False
+        )
+
+    def test_clear(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(a_mapper.c.id, b_mapper.c.t1id,)]
+        b1.obj().t1id = 8
+        eq_(b1.obj().__dict__['t1id'], 8)
+        sync.clear(b1, b_mapper, pairs)
+        eq_(b1.obj().__dict__['t1id'], None)
+
+    def test_clear_pk(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(a_mapper.c.id, b_mapper.c.id,)]
+        b1.obj().id = 8
+        eq_(b1.obj().__dict__['id'], 8)
+        assert_raises_message(
+            AssertionError,
+            "Dependency rule tried to blank-out primary key "
+            "column 't2.id' on instance '<B",
+            sync.clear, b1, b_mapper, pairs
+        )
+
+    def test_clear_unmapped(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(a_mapper.c.id, a_mapper.c.foo,)]
+        assert_raises_message(
+            orm_exc.UnmappedColumnError,
+            "Can't execute sync rule for destination "
+            r"column 't1.foo'; mapper 'Mapper\|B\|t2' does not "
+            "map this column.",
+            sync.clear, b1, b_mapper, pairs
+        )
+
+    def test_update(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        a1.obj().id = 10
+        a1.commit_all(a1.dict)
+        a1.obj().id = 12
+        pairs = [(a_mapper.c.id, b_mapper.c.id,)]
+        dest = {}
+        sync.update(a1, a_mapper, dest, "old_", pairs)
+        eq_(dest, {'id': 12, 'old_id': 10})
+
+    def test_update_unmapped(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(b_mapper.c.id, b_mapper.c.id,)]
+        dest = {}
+        assert_raises_message(
+            orm_exc.UnmappedColumnError,
+            "Can't execute sync rule for source column 't2.id'; "
+            r"mapper 'Mapper\|A\|t1' does not map this column.",
+            sync.update, a1, a_mapper, dest, "old_", pairs
+        )
+
+    def test_populate_dict(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        a1.obj().id = 10
+        pairs = [(a_mapper.c.id, b_mapper.c.id,)]
+        dest = {}
+        sync.populate_dict(a1, a_mapper, dest, pairs)
+        eq_(dest, {'id':10})
+
+    def test_populate_dict_unmapped(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        a1.obj().id = 10
+        pairs = [(b_mapper.c.id, b_mapper.c.id,)]
+        dest = {}
+        assert_raises_message(
+            orm_exc.UnmappedColumnError,
+            "Can't execute sync rule for source column 't2.id'; "
+            r"mapper 'Mapper\|A\|t1' does not map this column.",
+            sync.populate_dict, a1, a_mapper, dest, pairs
+        )
+
+    def test_source_modified_unmodified(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        a1.obj().id = 10
+        pairs = [(a_mapper.c.id, b_mapper.c.id,)]
+        eq_(
+            sync.source_modified(uowcommit, a1, a_mapper, pairs), 
+            False
+        )
+
+    def test_source_modified_no_pairs(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        eq_(
+            sync.source_modified(uowcommit, a1, a_mapper, []), 
+            False
+        )
+
+    def test_source_modified_modified(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        a1.obj().id = 10
+        a1.commit_all(a1.dict)
+        a1.obj().id = 12
+        pairs = [(a_mapper.c.id, b_mapper.c.id,)]
+        eq_(
+            sync.source_modified(uowcommit, a1, a_mapper, pairs), 
+            True
+        )
+
+    def test_source_modified_no_unmapped(self):
+        uowcommit, a1, b1, a_mapper, b_mapper = self._fixture()
+        pairs = [(b_mapper.c.id, b_mapper.c.id,)]
+        assert_raises_message(
+            orm_exc.UnmappedColumnError,
+            "Can't execute sync rule for source column 't2.id'; "
+            r"mapper 'Mapper\|A\|t1' does not map this column.",
+            sync.source_modified, uowcommit, a1, a_mapper, pairs
+        )