]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
copy list for __iadd__
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Dec 2021 02:39:59 +0000 (21:39 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Dec 2021 19:57:42 +0000 (14:57 -0500)
Fixed issue where a list mapped with :func:`_orm.relationship` would go
into an endless loop if in-place added to itself, i.e. the ``+=`` operator
were used, as well as if ``.extend()`` were given the same list.

Fixes: #7389
Change-Id: Idd5118420f8bc684d1ee36b2b6d4c5812f36cc4c

doc/build/changelog/unreleased_14/7389.rst [new file with mode: 0644]
lib/sqlalchemy/orm/collections.py
test/orm/test_collection.py

diff --git a/doc/build/changelog/unreleased_14/7389.rst b/doc/build/changelog/unreleased_14/7389.rst
new file mode 100644 (file)
index 0000000..887193c
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: orm, bug
+    :tickets: 7389
+
+    Fixed issue where a list mapped with :func:`_orm.relationship` would go
+    into an endless loop if in-place added to itself, i.e. the ``+=`` operator
+    were used, as well as if ``.extend()`` were given the same list.
+
index ccb88866e9629a898134e74b235072490500c0f7..d71c8426811db0e7076948713047b9c8459b54d0 100644 (file)
@@ -1252,7 +1252,7 @@ def _list_decorators():
 
     def extend(fn):
         def extend(self, iterable):
-            for value in iterable:
+            for value in list(iterable):
                 self.append(value)
 
         _tidy(extend)
@@ -1262,7 +1262,7 @@ def _list_decorators():
         def __iadd__(self, iterable):
             # list.__iadd__ takes any iterable and seems to let TypeError
             # raise as-is instead of returning NotImplemented
-            for value in iterable:
+            for value in list(iterable):
                 self.append(value)
             return self
 
index 9babe6366eb00e98f7821ee243c7963da571e643..806d98a69b51d294c87ac79382cbf020a1265d66 100644 (file)
@@ -2500,6 +2500,19 @@ class CustomCollectionsTest(fixtures.MappedTest):
         assert control == p.children
         assert control == list(p.children)
 
+        # test #7389
+        if hasattr(p.children, "__iadd__"):
+            control += control
+            p.children += p.children
+            assert control == list(p.children)
+
+        control[:] = [o]
+        p.children[:] = [o]
+        if hasattr(p.children, "extend"):
+            control.extend(control)
+            p.children.extend(p.children)
+            assert control == list(p.children)
+
     def test_custom(self):
         someothertable, sometable = (
             self.tables.someothertable,