summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-10-01 12:14:34 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2013-10-01 12:14:34 -0400
commit3d4d93332951a790e7d74afc5a3e13ed2523fe90 (patch)
treef46fca43a18e7cc99d9333381c070b06404dc6fc
parent94d421ca2f2d9f45b5feb4419a34b97a50b8d90b (diff)
downloadsqlalchemy-3d4d93332951a790e7d74afc5a3e13ed2523fe90.tar.gz
- add support for removal of instance methods as event listeners, taking
into account the id() of the function itself and self, [ticket:2832]
-rw-r--r--lib/sqlalchemy/event/registry.py8
-rw-r--r--test/base/test_events.py26
2 files changed, 32 insertions, 2 deletions
diff --git a/lib/sqlalchemy/event/registry.py b/lib/sqlalchemy/event/registry.py
index 330650e56..868dc28ed 100644
--- a/lib/sqlalchemy/event/registry.py
+++ b/lib/sqlalchemy/event/registry.py
@@ -12,6 +12,7 @@ from __future__ import absolute_import
import weakref
import collections
+import types
from .. import exc
@@ -130,13 +131,16 @@ class _EventKey(object):
self.target = target
self.identifier = identifier
self.fn = fn
+ if isinstance(fn, types.MethodType):
+ self.fn_key = id(fn.__func__), id(fn.__self__)
+ else:
+ self.fn_key = id(fn)
self.fn_wrap = _fn_wrap
self.dispatch_target = dispatch_target
@property
def _key(self):
- return (id(self.target), self.identifier, id(self.fn))
-
+ return (id(self.target), self.identifier, self.fn_key)
def with_wrapper(self, fn_wrap):
if fn_wrap is self._listen_fn:
diff --git a/test/base/test_events.py b/test/base/test_events.py
index d2bfb0932..8673c9baf 100644
--- a/test/base/test_events.py
+++ b/test/base/test_events.py
@@ -966,6 +966,32 @@ class RemovalTest(fixtures.TestBase):
eq_(m1.mock_calls, [call("x")])
+ def test_instance(self):
+ Target = self._fixture()
+
+ class Foo(object):
+ def __init__(self):
+ self.mock = Mock()
+
+ def evt(self, arg):
+ self.mock(arg)
+
+ f1 = Foo()
+ f2 = Foo()
+
+ event.listen(Target, "event_one", f1.evt)
+ event.listen(Target, "event_one", f2.evt)
+
+ t1 = Target()
+ t1.dispatch.event_one("x")
+
+ event.remove(Target, "event_one", f1.evt)
+
+ t1.dispatch.event_one("y")
+
+ eq_(f1.mock.mock_calls, [call("x")])
+ eq_(f2.mock.mock_calls, [call("x"), call("y")])
+
def test_propagate(self):
Target = self._fixture()