diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-01-12 17:21:35 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-01-12 17:21:35 -0500 |
| commit | 576224edd01f96bb505f9162282cfa9ba6efcb46 (patch) | |
| tree | 80606787b39fd81dea233a197f655277c6a246d5 /lib/sqlalchemy/event.py | |
| parent | 56b1f4c8845373b6680d6ab09dcefe36eaeb12fb (diff) | |
| download | sqlalchemy-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.py | 17 |
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""" |
