]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Fix WeakSequence circular reference
authorCarson Ip <carsonip715@gmail.com>
Fri, 27 Dec 2019 17:05:30 +0000 (12:05 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 27 Dec 2019 19:38:25 +0000 (14:38 -0500)
Fixed a reference cycle which could impact the GC behavior of the
:class:`.WeakSequence` object, currently used within one place in certain
mapper configurations.  The issue only affects configuration-time
structures. Pull request courtesy Carson Ip.

Fixes: #5050
Closes: #5051
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/5051
Pull-request-sha: db672f45f4f139722edd2dcc6b0c19892725c9de

Change-Id: I72673a33e655c44b68283ec1a2d7358b904e90ae
(cherry picked from commit f7a7af70c4f6f07011fa2d521fb1560917896427)

doc/build/changelog/unreleased_13/5050.rst [new file with mode: 0644]
lib/sqlalchemy/util/_collections.py
test/base/test_utils.py

diff --git a/doc/build/changelog/unreleased_13/5050.rst b/doc/build/changelog/unreleased_13/5050.rst
new file mode 100644 (file)
index 0000000..9831406
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, orm
+    :tickets: 5050
+
+    Fixed a reference cycle which could impact the GC behavior of the
+    :class:`.WeakSequence` object, currently used within one place in certain
+    mapper configurations.  The issue only affects configuration-time
+    structures. Pull request courtesy Carson Ip.
+
index 75e1727df6d8dfd9b6bbd88c20ceb353d6aaac3a..04409cfd91c78e7e5ca7573fcfdfdc593b2d8215 100644 (file)
@@ -676,16 +676,18 @@ class IdentitySet(object):
 
 class WeakSequence(object):
     def __init__(self, __elements=()):
+        def _remove(item, selfref=weakref.ref(self)):
+            self = selfref()
+            if self is not None:
+                self._storage.remove(item)
+        self._remove = _remove
         self._storage = [
-            weakref.ref(element, self._remove) for element in __elements
+            weakref.ref(element, _remove) for element in __elements
         ]
 
     def append(self, item):
         self._storage.append(weakref.ref(item, self._remove))
 
-    def _remove(self, ref):
-        self._storage.remove(ref)
-
     def __len__(self):
         return len(self._storage)
 
index 23436a6fd61510efaad15716cf7ba92f34974355..eb4c3db41b68823c2033a271d81a3d7e94a54cac 100644 (file)
@@ -185,6 +185,19 @@ class WeakSequenceTest(fixtures.TestBase):
         eq_(len(w), 2)
         eq_(len(w._storage), 2)
 
+    @testing.requires.predictable_gc
+    def test_cleanout_container(self):
+        import weakref
+
+        class Foo(object):
+            pass
+
+        f = Foo()
+        w = WeakSequence([f])
+        w_wref = weakref.ref(w)
+        del w
+        eq_(w_wref(), None)
+
 
 class OrderedDictTest(fixtures.TestBase):
     def test_odict(self):