summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2017-06-05 15:49:04 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2017-06-05 15:49:04 -0400
commite8ad3988621a3caa69074fae8e9320bcabcf806d (patch)
treee94d6b745e64c7f37111afe11f0c709eed45ee8d
parentbb6a1f690d4a749df44a1ef329b66f71205968fe (diff)
downloadsqlalchemy-e8ad3988621a3caa69074fae8e9320bcabcf806d.tar.gz
Implement in-place mutation operators for MutableSet, MutableList
Implemented in-place mutation operators ``__ior__``, ``__iand__``, ``__ixor__`` and ``__isub__`` for :class:`.mutable.MutableSet` and ``__iadd__`` for :class:`.mutable.MutableList` so that change events are fired off when these mutator methods are used to alter the collection. Change-Id: Ib357a96d3b06c5deb6b53eb304a8b9f1dc9e9ede Fixes: #3853
-rw-r--r--doc/build/changelog/changelog_12.rst14
-rw-r--r--doc/build/changelog/migration_12.rst19
-rw-r--r--lib/sqlalchemy/ext/mutable.py20
-rw-r--r--test/ext/test_mutable.py60
4 files changed, 113 insertions, 0 deletions
diff --git a/doc/build/changelog/changelog_12.rst b/doc/build/changelog/changelog_12.rst
index ee6eb7f65..362e731a3 100644
--- a/doc/build/changelog/changelog_12.rst
+++ b/doc/build/changelog/changelog_12.rst
@@ -13,6 +13,20 @@
.. changelog::
:version: 1.2.0b1
+ .. change:: 3853
+ :tags: bug, ext
+ :tickets: 3853
+
+ Implemented in-place mutation operators ``__ior__``, ``__iand__``,
+ ``__ixor__`` and ``__isub__`` for :class:`.mutable.MutableSet`
+ and ``__iadd__`` for :class:`.mutable.MutableList` so that change
+ events are fired off when these mutator methods are used to alter the
+ collection.
+
+ .. seealso::
+
+ :ref:`change_3853`
+
.. change:: 4003
:tags: feature, oracle
diff --git a/doc/build/changelog/migration_12.rst b/doc/build/changelog/migration_12.rst
index 281bda936..4d4c9e247 100644
--- a/doc/build/changelog/migration_12.rst
+++ b/doc/build/changelog/migration_12.rst
@@ -411,6 +411,25 @@ parameter.
:ticket:`3991`
+.. _change_3853:
+
+In-place mutation operators work for MutableSet, MutableList
+------------------------------------------------------------
+
+Implemented the in-place mutation operators ``__ior__``, ``__iand__``,
+``__ixor__`` and ``__isub__`` for :class:`.mutable.MutableSet` and ``__iadd__``
+for :class:`.mutable.MutableList`. While these
+methods would successfully update the collection previously, they would
+not correctly fire off change events. The operators mutate the collection
+as before but additionally emit the correct change event so that the change
+becomes part of the next flush process::
+
+ model = session.query(MyModel).first()
+ model.json_set &= {1, 3}
+
+
+:ticket:`3853`
+
New Features and Improvements - Core
====================================
diff --git a/lib/sqlalchemy/ext/mutable.py b/lib/sqlalchemy/ext/mutable.py
index ccaeb6aa3..b72303bc8 100644
--- a/lib/sqlalchemy/ext/mutable.py
+++ b/lib/sqlalchemy/ext/mutable.py
@@ -806,6 +806,10 @@ class MutableList(Mutable, list):
list.extend(self, x)
self.changed()
+ def __iadd__(self, x):
+ self.extend(x)
+ return self
+
def insert(self, i, x):
list.insert(self, i, x)
self.changed()
@@ -885,6 +889,22 @@ class MutableSet(Mutable, set):
set.symmetric_difference_update(self, *arg)
self.changed()
+ def __ior__(self, other):
+ self.update(other)
+ return self
+
+ def __iand__(self, other):
+ self.intersection_update(other)
+ return self
+
+ def __ixor__(self, other):
+ self.symmetric_difference_update(other)
+ return self
+
+ def __isub__(self, other):
+ self.difference_update(other)
+ return self
+
def add(self, elem):
set.add(self, elem)
self.changed()
diff --git a/test/ext/test_mutable.py b/test/ext/test_mutable.py
index 366b2006f..e90ea7af2 100644
--- a/test/ext/test_mutable.py
+++ b/test/ext/test_mutable.py
@@ -401,6 +401,18 @@ class _MutableListTestBase(_MutableListTestFixture):
eq_(f1.data, [1, 2, 5])
+ def test_operator_extend(self):
+ sess = Session()
+
+ f1 = Foo(data=[1, 2])
+ sess.add(f1)
+ sess.commit()
+
+ f1.data += [5]
+ sess.commit()
+
+ eq_(f1.data, [1, 2, 5])
+
def test_insert(self):
sess = Session()
@@ -561,6 +573,18 @@ class _MutableSetTestBase(_MutableSetTestFixture):
eq_(f1.data, set([1, 2, 5]))
+ def test_binary_update(self):
+ sess = Session()
+
+ f1 = Foo(data=set([1, 2]))
+ sess.add(f1)
+ sess.commit()
+
+ f1.data |= set([2, 5])
+ sess.commit()
+
+ eq_(f1.data, set([1, 2, 5]))
+
def test_intersection_update(self):
sess = Session()
@@ -573,6 +597,18 @@ class _MutableSetTestBase(_MutableSetTestFixture):
eq_(f1.data, set([2]))
+ def test_binary_intersection_update(self):
+ sess = Session()
+
+ f1 = Foo(data=set([1, 2]))
+ sess.add(f1)
+ sess.commit()
+
+ f1.data &= set([2, 5])
+ sess.commit()
+
+ eq_(f1.data, set([2]))
+
def test_difference_update(self):
sess = Session()
@@ -585,6 +621,18 @@ class _MutableSetTestBase(_MutableSetTestFixture):
eq_(f1.data, set([1]))
+ def test_operator_difference_update(self):
+ sess = Session()
+
+ f1 = Foo(data=set([1, 2]))
+ sess.add(f1)
+ sess.commit()
+
+ f1.data -= set([2, 5])
+ sess.commit()
+
+ eq_(f1.data, set([1]))
+
def test_symmetric_difference_update(self):
sess = Session()
@@ -597,6 +645,18 @@ class _MutableSetTestBase(_MutableSetTestFixture):
eq_(f1.data, set([1, 5]))
+ def test_binary_symmetric_difference_update(self):
+ sess = Session()
+
+ f1 = Foo(data=set([1, 2]))
+ sess.add(f1)
+ sess.commit()
+
+ f1.data ^= set([2, 5])
+ sess.commit()
+
+ eq_(f1.data, set([1, 5]))
+
def test_remove(self):
sess = Session()