]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- fixed bug with session.dirty when using "mutable scalars"
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 9 Jan 2008 18:52:35 +0000 (18:52 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 9 Jan 2008 18:52:35 +0000 (18:52 +0000)
(such as PickleTypes)

- added a more descriptive error message when flushing on a
relation() that has non-locally-mapped columns in its primary or
secondary join condition

CHANGES
lib/sqlalchemy/exceptions.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/sync.py
lib/sqlalchemy/orm/unitofwork.py
test/orm/unitofwork.py

diff --git a/CHANGES b/CHANGES
index cbceea4d998135db3283d2877a43a283da8035ed..f808b369b9a5a1464b3aa21fa0a1dbc6a696a933 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -13,6 +13,14 @@ CHANGES
       
     - fixed bug in union() so that select() statements which don't derive
       from FromClause objects can be unioned
+
+- orm
+    - fixed bug with session.dirty when using "mutable scalars" 
+      (such as PickleTypes)
+      
+    - added a more descriptive error message when flushing on a 
+      relation() that has non-locally-mapped columns in its primary or
+      secondary join condition
       
 - dialects
     - Fixed reflection of mysql empty string column defaults.
index 8dbbb91c842a7dfd89e22a2c26a9846379a9b5a6..02cee506322ce682f98097edb7e373fab34be614 100644 (file)
@@ -46,7 +46,10 @@ class InvalidRequestError(SQLAlchemyError):
     This error generally corresponds to runtime state errors.
     """
 
-
+class UnmappedColumnError(InvalidRequestError):
+    """A mapper was asked to return mapped information about a column 
+    which it does not map"""
+    
 class NoSuchTableError(InvalidRequestError):
     """SQLAlchemy was asked to load a table's definition from the
     database, but the table doesn't exist.
index fc62c773e939f893b6e0a2cda87ddd6ec954a1b5..2df7926aa25a16d6ce2f60abebbe10b38b113811 100644 (file)
@@ -901,9 +901,9 @@ class Mapper(object):
         except KeyError:
             prop = self.__props.get(column.key, None)
             if prop:
-                raise exceptions.InvalidRequestError("Column '%s.%s' is not available, due to conflicting property '%s':%s" % (column.table.name, column.name, column.key, repr(prop)))
+                raise exceptions.UnmappedColumnError("Column '%s.%s' is not available, due to conflicting property '%s':%s" % (column.table.name, column.name, column.key, repr(prop)))
             else:
-                raise exceptions.InvalidRequestError("No column %s.%s is configured on mapper %s..." % (column.table.name, column.name, str(self)))
+                raise exceptions.UnmappedColumnError("No column %s.%s is configured on mapper %s..." % (column.table.name, column.name, str(self)))
         
     def _get_state_attr_by_column(self, state, column):
         return self._get_col_to_prop(column).getattr(state, column)
index 678e5e7bd0f03820956d3db6e50c9ca33864060f..a80252c847c015623bf20332489c9646762237c5 100644 (file)
@@ -117,7 +117,7 @@ class SyncRule(object):
         self.issecondary = issecondary
         self.dest_mapper = dest_mapper
         self.dest_column = dest_column
-
+        
         #print "SyncRule", source_mapper, source_column, dest_column, dest_mapper
 
     def dest_primary_key(self):
@@ -129,8 +129,17 @@ class SyncRule(object):
             self._dest_primary_key = self.dest_mapper is not None and self.dest_column in self.dest_mapper._pks_by_table[self.dest_column.table] and not self.dest_mapper.allow_null_pks
             return self._dest_primary_key
     
+    def _raise_col_to_prop(self, isdest):
+        if isdest:
+            raise exceptions.UnmappedColumnError("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)." % (self.dest_column, self.dest_mapper))
+        else:
+            raise exceptions.UnmappedColumnError("Can't execute sync rule for source column '%s'; mapper '%s' does not map this column.  Try using an explicit `foreign_keys` collection which does not include destination column '%s' (or use a viewonly=True relation)." % (self.source_column, self.source_mapper, self.dest_column))
+                
     def source_changes(self, uowcommit, source):
-        prop = self.source_mapper._columntoproperty[self.source_column]
+        try:
+            prop = self.source_mapper._get_col_to_prop(self.source_column)
+        except exceptions.UnmappedColumnError:
+            self._raise_col_to_prop(False)
         (added, unchanged, deleted) = uowcommit.get_attribute_history(source, prop.key, passive=True)
         return bool(added and deleted)
     
@@ -139,8 +148,11 @@ class SyncRule(object):
             source = parent
         elif self.issecondary is True:
             source = child
-        oldvalue = self.source_mapper._get_committed_attr_by_column(source.obj(), self.source_column)
-        value = self.source_mapper._get_state_attr_by_column(source, self.source_column)
+        try:
+            oldvalue = self.source_mapper._get_committed_attr_by_column(source.obj(), self.source_column)
+            value = self.source_mapper._get_state_attr_by_column(source, self.source_column)
+        except exceptions.UnmappedColumnError:
+            self._raise_col_to_prop(False)
         dest[self.dest_column.key] = value
         dest[old_prefix + self.dest_column.key] = oldvalue
         
@@ -156,7 +168,10 @@ class SyncRule(object):
             value = None
             clearkeys = True
         else:
-            value = self.source_mapper._get_state_attr_by_column(source, self.source_column)
+            try:
+                value = self.source_mapper._get_state_attr_by_column(source, self.source_column)
+            except exceptions.UnmappedColumnError:
+                self._raise_col_to_prop(False)
         if isinstance(dest, dict):
             dest[self.dest_column.key] = value
         else:
@@ -165,7 +180,10 @@ class SyncRule(object):
 
             if logging.is_debug_enabled(self.logger):
                 self.logger.debug("execute() instances: %s(%s)->%s(%s) ('%s')" % (mapperutil.state_str(source), str(self.source_column), mapperutil.state_str(dest), str(self.dest_column), value))
-            self.dest_mapper._set_state_attr_by_column(dest, self.dest_column, value)
+            try:
+                self.dest_mapper._set_state_attr_by_column(dest, self.dest_column, value)
+            except exceptions.UnmappedColumnError:
+                self._raise_col_to_prop(True)
 
 SyncRule.logger = logging.class_logger(SyncRule)
 
index e71488547dfc03f466c0272ec79e1870d6f239c7..05c9388b309fefdaf9a40d090bd692de415220b4 100644 (file)
@@ -158,7 +158,7 @@ class UnitOfWork(object):
             if x._state not in self.deleted 
             and (
                 x._state.modified
-                or (x.__class__._class_state.has_mutable_scalars and x.state.is_modified())
+                or (x.__class__._class_state.has_mutable_scalars and x._state.is_modified())
             )
             ])
 
index 47ce70fa7ad4ed7e5133978cff618b9b30523f92..1ff3bda85e8675536ca331a8077e064f5c4af6eb 100644 (file)
@@ -272,6 +272,7 @@ class MutableTypesTest(ORMTest):
         f2 = Session.query(Foo).get_by(id=f1.id)
         assert f2.data == f1.data
         f2.data.y = 19
+        assert f2 in Session.dirty
         Session.commit()
         Session.close()
         f3 = Session.query(Foo).get_by(id=f1.id)