]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug in mutable extension as well as
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 19 Mar 2014 15:09:38 +0000 (11:09 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 19 Mar 2014 15:12:24 +0000 (11:12 -0400)
:func:`.attributes.flag_modified` where the change event would not be
propagated if the attribute had been reassigned to itself.
fixes #2997

Conflicts:
lib/sqlalchemy/orm/state.py
test/orm/test_attributes.py

doc/build/changelog/changelog_08.rst
lib/sqlalchemy/ext/mutable.py
lib/sqlalchemy/orm/attributes.py
lib/sqlalchemy/orm/state.py
test/ext/test_mutable.py
test/orm/test_attributes.py

index a0df6a28794d59dcc3cc506c6d0725eae0378ae8..809b38950144927809edc122df6fa69185e58cf6 100644 (file)
 .. changelog::
     :version: 0.8.6
 
+    .. change::
+        :tags: bug, ext
+        :versions: 0.9.4
+        :tickets: 2997
+
+        Fixed bug in mutable extension as well as
+        :func:`.attributes.flag_modified` where the change event would not be
+        propagated if the attribute had been reassigned to itself.
+
     .. change::
         :tags: bug, orm
         :versions: 0.9.4
index 293258b2cc7a4c26d0dff8b464fca4df9ae41e04..d5acb18710e21e6e494b065842912668786e573a 100644 (file)
@@ -437,6 +437,9 @@ class MutableBase(object):
             outgoing.
 
             """
+            if value is oldvalue:
+                return value
+
             if not isinstance(value, cls):
                 value = cls.coerce(key, value)
             if value is not None:
index aaca9e927d4a05a1223ddc44d37d82b0fdf14001..cbbdb477b865a1cd926a71547127199c9078cdf0 100644 (file)
@@ -1555,4 +1555,4 @@ def flag_modified(instance, key):
     """
     state, dict_ = instance_state(instance), instance_dict(instance)
     impl = state.manager[key].impl
-    state._modified_event(dict_, impl, NO_VALUE)
+    state._modified_event(dict_, impl, NO_VALUE, force=True)
index bbe5bf56f42f99b693d6b63562bbdc39a2ac4808..4a00cfe9db2548338499f12302c12a37ae011896 100644 (file)
@@ -427,8 +427,8 @@ class InstanceState(interfaces._InspectionAttr):
     def _instance_dict(self):
         return None
 
-    def _modified_event(self, dict_, attr, previous, collection=False):
-        if attr.key not in self.committed_state:
+    def _modified_event(self, dict_, attr, previous, collection=False, force=False):
+        if attr.key not in self.committed_state or force:
             if collection:
                 if previous is NEVER_SET:
                     if attr.key in dict_:
index bda9e5382e7ffa77ba57c236a34dc6ab56665959..268af6e49bbd2a28887805cf1a6f5bf5ef8b9c6d 100644 (file)
@@ -96,6 +96,17 @@ class _MutableDictTestBase(object):
         sess.commit()
         eq_(f1.data, {'b': 'c'})
 
+    def test_replace_itself_still_ok(self):
+        sess = Session()
+        f1 = Foo(data={'a': 'b'})
+        sess.add(f1)
+        sess.flush()
+
+        f1.data = f1.data
+        f1.data['b'] = 'c'
+        sess.commit()
+        eq_(f1.data, {'a': 'b', 'b': 'c'})
+
     def test_pickle_parent(self):
         sess = Session()
 
index dbe82f585135fbb8e52f60139673cf6de64410e0..f8cb1f75d9e2f9c1c8e42d7fc525782ea6f1059c 100644 (file)
@@ -1850,6 +1850,23 @@ class HistoryTest(fixtures.TestBase):
         f.someattr = ['a']
         eq_(self._someattr_history(f), ([['a']], (), ()))
 
+
+    def test_scalar_inplace_mutation_replace_self_flag_modified_set(self):
+        Foo = self._fixture(uselist=False, useobject=False,
+                                active_history=False)
+        f = Foo()
+        f.someattr = {'a': 'b'}
+        self._commit_someattr(f)
+        eq_(self._someattr_history(f), ((), [{'a': 'b'}], ()))
+
+        # set the attribute to itself; this places a copy
+        # in committed_state
+        f.someattr = f.someattr
+
+        attributes.flag_modified(f, 'someattr')
+        eq_(self._someattr_history(f), ([{'a': 'b'}], (), ()))
+
+
     def test_use_object_init(self):
         Foo, Bar = self._two_obj_fixture(uselist=False)
         f = Foo()