From: Mike Bayer Date: Tue, 26 Oct 2010 20:12:04 +0000 (-0400) Subject: - Fixed bug whereby a non-"mutable" attribute modified event X-Git-Tag: rel_0_7b1~287 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0d00f470356c26fc18e890ede4620c10b5086a85;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - 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. --- diff --git a/CHANGES b/CHANGES index 2acf1b76f6..3ccf2d28eb 100644 --- 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 diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py index 65ecc9a889..5eea53ac66 100644 --- a/lib/sqlalchemy/__init__.py +++ b/lib/sqlalchemy/__init__.py @@ -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 diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index e6502df8ca..ad1d4a8f0d 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -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) diff --git a/test/orm/test_unitofwork.py b/test/orm/test_unitofwork.py index c95836055b..52a93a122c 100644 --- a/test/orm/test_unitofwork.py +++ b/test/orm/test_unitofwork.py @@ -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):