summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/event.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-01-12 17:21:35 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2013-01-12 17:21:35 -0500
commit576224edd01f96bb505f9162282cfa9ba6efcb46 (patch)
tree80606787b39fd81dea233a197f655277c6a246d5 /lib/sqlalchemy/event.py
parent56b1f4c8845373b6680d6ab09dcefe36eaeb12fb (diff)
downloadsqlalchemy-576224edd01f96bb505f9162282cfa9ba6efcb46.tar.gz
- add workaround for sqlite memusage tests, so no longer need to count to 220/skip tests
- Fixed potential memory leak which could occur if an arbitrary number of :class:`.sessionmaker` objects were created. The anonymous subclass created by the sessionmaker, when dereferenced, would not be garbage collected due to remaining class-level references from the event package. This issue also applies to any custom system that made use of ad-hoc subclasses in conjunction with an event dispatcher. Also in 0.7.10. [ticket:2650]
Diffstat (limited to 'lib/sqlalchemy/event.py')
-rw-r--r--lib/sqlalchemy/event.py17
1 files changed, 13 insertions, 4 deletions
diff --git a/lib/sqlalchemy/event.py b/lib/sqlalchemy/event.py
index 6293572a3..f28f19ee9 100644
--- a/lib/sqlalchemy/event.py
+++ b/lib/sqlalchemy/event.py
@@ -8,6 +8,7 @@
from . import util, exc
from itertools import chain
+import weakref
CANCEL = util.symbol('CANCEL')
NO_RETVAL = util.symbol('NO_RETVAL')
@@ -242,11 +243,12 @@ class _DispatchDescriptor(object):
def __init__(self, fn):
self.__name__ = fn.__name__
self.__doc__ = fn.__doc__
- self._clslevel = util.defaultdict(list)
- self._empty_listeners = {}
+ self._clslevel = weakref.WeakKeyDictionary()
+ self._empty_listeners = weakref.WeakKeyDictionary()
def _contains(self, cls, evt):
- return evt in self._clslevel[cls]
+ return cls in self._clslevel and \
+ evt in self._clslevel[cls]
def insert(self, obj, target, propagate):
assert isinstance(target, type), \
@@ -258,6 +260,8 @@ class _DispatchDescriptor(object):
if cls is not target and cls not in self._clslevel:
self.update_subclass(cls)
else:
+ if cls not in self._clslevel:
+ self._clslevel[cls] = []
self._clslevel[cls].insert(0, obj)
def append(self, obj, target, propagate):
@@ -271,9 +275,13 @@ class _DispatchDescriptor(object):
if cls is not target and cls not in self._clslevel:
self.update_subclass(cls)
else:
+ if cls not in self._clslevel:
+ self._clslevel[cls] = []
self._clslevel[cls].append(obj)
def update_subclass(self, target):
+ if target not in self._clslevel:
+ self._clslevel[target] = []
clslevel = self._clslevel[target]
for cls in target.__mro__[1:]:
if cls in self._clslevel:
@@ -288,7 +296,8 @@ class _DispatchDescriptor(object):
while stack:
cls = stack.pop(0)
stack.extend(cls.__subclasses__())
- self._clslevel[cls].remove(obj)
+ if cls in self._clslevel:
+ self._clslevel[cls].remove(obj)
def clear(self):
"""Clear all class level listeners"""