]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug whereby a non-"mutable" attribute modified event
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 26 Oct 2010 20:12:04 +0000 (16:12 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 26 Oct 2010 20:12:04 +0000 (16:12 -0400)
which occurred on an object that was clean except for
preceding mutable attribute changes would fail to strongly
reference itself in the identity map. This would cause the
object to be garbage collected, losing track of any changes
that weren't previously saved in the "mutable changes"
dictionary.

CHANGES
lib/sqlalchemy/__init__.py
lib/sqlalchemy/orm/state.py
test/orm/test_unitofwork.py

diff --git a/CHANGES b/CHANGES
index 2acf1b76f6e21b3a36df412aeafcc211c0df671b..3ccf2d28eb63f80829903ce85df142d2a2160b52 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,17 @@
 =======
 CHANGES
 =======
+0.6.6
+=====
+- orm
+  - Fixed bug whereby a non-"mutable" attribute modified event
+    which occurred on an object that was clean except for
+    preceding mutable attribute changes would fail to strongly
+    reference itself in the identity map. This would cause the
+    object to be garbage collected, losing track of any changes
+    that weren't previously saved in the "mutable changes"
+    dictionary.
+    
 0.6.5
 =====
 - orm
index 65ecc9a889a0c7e0c4ab05ae2a99065c8be38bbe..5eea53ac665b9eaa7e3b977e74dcfc455b07e865 100644 (file)
@@ -115,6 +115,6 @@ from sqlalchemy.engine import create_engine, engine_from_config
 __all__ = sorted(name for name, obj in locals().items()
                  if not (name.startswith('_') or inspect.ismodule(obj)))
                  
-__version__ = '0.6.5'
+__version__ = '0.6.6'
 
 del inspect, sys
index e6502df8cac0ed23bb6f8b870c3cecdd63521ea5..ad1d4a8f0da14a0059aadd6cda35db95411c08a1 100644 (file)
@@ -338,8 +338,14 @@ class InstanceState(object):
                 previous = attr.copy(previous)
 
             self.committed_state[attr.key] = previous
-
-        if not self.modified:
+        
+        
+        # the "or not self.modified" is defensive at 
+        # this point.  The assertion below is expected
+        # to be True:
+        # assert self._strong_obj is None or self.modified
+        
+        if self._strong_obj is None or not self.modified:
             instance_dict = self._instance_dict()
             if instance_dict:
                 instance_dict._modified.add(self)
index c95836055b8b3d74add799ad138dda330b786570..52a93a122c8349b598ace6debe1bfc114e0d6295 100644 (file)
@@ -359,6 +359,25 @@ class MutableTypesTest(_base.MappedTest):
         gc.collect()
         f1 = session.query(Foo).first()
         assert not attributes.instance_state(f1).modified
+
+    @testing.resolve_artifact_names
+    def test_modified_after_mutable_change(self):
+        f1 = Foo(data = pickleable.Bar(4, 5), val=u'some val')
+        session = Session()
+        session.add(f1)
+        session.commit()
+        f1.data.x = 10
+        f1.data.y = 15
+        f1.val=u'some new val'
+
+        assert sa.orm.attributes.instance_state(f1)._strong_obj is not None
+        
+        del f1
+        session.commit()
+        eq_(
+            session.query(Foo.val).all(),
+            [('some new val', )]
+        )
         
     @testing.resolve_artifact_names
     def test_unicode(self):