diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-12-27 15:02:31 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-12-30 14:07:18 -0500 |
| commit | 04fbb9e63c098dd2de40b545eed210dfd93893ce (patch) | |
| tree | f509e09f71c9a382b2d7934cf81262ad019df377 /lib/sqlalchemy/util | |
| parent | 9d4a58d35c53484a1de66396139fc34cd65f5be8 (diff) | |
| download | sqlalchemy-04fbb9e63c098dd2de40b545eed210dfd93893ce.tar.gz | |
Test for short term reference cycles and resolve as many as possible
Added test support and repaired a wide variety of unnecessary reference
cycles created for short-lived objects, mostly in the area of ORM queries.
Fixes: #5056
Change-Id: Ifd93856eba550483f95f9ae63d49f36ab068b85a
Diffstat (limited to 'lib/sqlalchemy/util')
| -rw-r--r-- | lib/sqlalchemy/util/__init__.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/util/_collections.py | 20 |
2 files changed, 20 insertions, 2 deletions
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py index 78155b08a..a0821a3cc 100644 --- a/lib/sqlalchemy/util/__init__.py +++ b/lib/sqlalchemy/util/__init__.py @@ -31,7 +31,6 @@ from ._collections import OrderedDict # noqa from ._collections import OrderedIdentitySet # noqa from ._collections import OrderedProperties # noqa from ._collections import OrderedSet # noqa -from ._collections import populate_column_dict # noqa from ._collections import PopulateDict # noqa from ._collections import Properties # noqa from ._collections import ScopedRegistry # noqa @@ -42,6 +41,7 @@ from ._collections import to_set # noqa from ._collections import unique_list # noqa from ._collections import UniqueAppender # noqa from ._collections import update_copy # noqa +from ._collections import WeakPopulateDict # noqa from ._collections import WeakSequence # noqa from .compat import b # noqa from .compat import b64decode # noqa diff --git a/lib/sqlalchemy/util/_collections.py b/lib/sqlalchemy/util/_collections.py index 04409cfd9..7b46bc8e6 100644 --- a/lib/sqlalchemy/util/_collections.py +++ b/lib/sqlalchemy/util/_collections.py @@ -676,10 +676,13 @@ class IdentitySet(object): class WeakSequence(object): def __init__(self, __elements=()): + # adapted from weakref.WeakKeyDictionary, prevent reference + # cycles in the collection itself 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, _remove) for element in __elements @@ -737,6 +740,22 @@ class PopulateDict(dict): return val +class WeakPopulateDict(dict): + """Like PopulateDict, but assumes a self + a method and does not create + a reference cycle. + + """ + + def __init__(self, creator_method): + self.creator = creator_method.__func__ + weakself = creator_method.__self__ + self.weakself = weakref.ref(weakself) + + def __missing__(self, key): + self[key] = val = self.creator(self.weakself(), key) + return val + + # Define collections that are capable of storing # ColumnElement objects as hashable keys/elements. # At this point, these are mostly historical, things @@ -744,7 +763,6 @@ class PopulateDict(dict): column_set = set column_dict = dict ordered_column_set = OrderedSet -populate_column_dict = PopulateDict _getters = PopulateDict(operator.itemgetter) |
