]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- add support for removal of instance methods as event listeners, taking
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 1 Oct 2013 16:14:34 +0000 (12:14 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 1 Oct 2013 16:14:34 +0000 (12:14 -0400)
into account the id() of the function itself and self, [ticket:2832]

lib/sqlalchemy/event/registry.py
test/base/test_events.py

index 330650e562245c2ebd13dbfe5855e53878dd8742..868dc28edcd3ea5449fc9f2ce73eb9c8630b81a1 100644 (file)
@@ -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:
index d2bfb0932c53a9ad7429f24bd37f519291f76695..8673c9baf0c5c914524e9281a732e9fc957d72b4 100644 (file)
@@ -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()