for evt_cls in _registrars[identifier]:
tgt = evt_cls.accept_with(target)
if tgt is not None:
+ if kw.pop('propagate', False):
+ fn._sa_event_propagate = True
tgt.dispatch.listen(fn, identifier, tgt, *args, **kw)
return
raise exc.InvalidRequestError("No such event %s for target %s" %
def descriptors(self):
return (getattr(self, k) for k in dir(self) if k.startswith("on_"))
- def update(self, other):
+ def update(self, other, only_propagate=True):
"""Populate from the listeners in another :class:`_Dispatch`
object."""
for ls in other.descriptors:
- getattr(self, ls.name).update(ls)
+ getattr(self, ls.name).update(ls, only_propagate=only_propagate)
class _EventMeta(type):
"""Intercept new Event subclasses and create
def __nonzero__(self):
return bool(self.listeners or self.parent_listeners)
- def update(self, other):
+ def update(self, other, only_propagate=True):
"""Populate from the listeners in another :class:`_Dispatch`
object."""
existing_listener_set = set(existing_listeners)
existing_listeners.extend([l for l
in other.listeners
- if l not in existing_listener_set])
+ if l not in existing_listener_set
+ and not only_propagate or getattr(l, '_sa_event_propagate', False)
+ ])
def append(self, obj, target):
if obj not in self.listeners:
ls_meth(self, instance)
return reconstruct
event.listen(go(ls_meth), 'on_load',
- self.class_manager, raw=False)
+ self.class_manager, raw=False, propagate=True)
elif meth == 'init_instance':
def go(ls_meth):
def init_instance(instance, args, kwargs):
instance, args, kwargs)
return init_instance
event.listen(go(ls_meth), 'on_init',
- self.class_manager, raw=False)
+ self.class_manager, raw=False, propagate=True)
elif meth == 'init_failed':
def go(ls_meth):
def init_failed(instance, args, kwargs):
return init_failed
event.listen(go(ls_meth), 'on_init_failure',
- self.class_manager, raw=False)
+ self.class_manager, raw=False, propagate=True)
else:
event.listen(ls_meth, "on_%s" % meth, self,
- raw=False, retval=True)
+ raw=False, retval=True, propagate=True)
def instrument_class(self, mapper, class_):
]
)
+class TestPropagate(TestBase):
+ def setUp(self):
+ global Target
+
+ class TargetEvents(event.Events):
+ def on_event_one(self, arg):
+ pass
+
+ def on_event_two(self, arg):
+ pass
+
+ class Target(object):
+ dispatch = event.dispatcher(TargetEvents)
+
+
+ def test_propagate(self):
+ result = []
+ def listen_one(target, arg):
+ result.append((target, arg))
+
+ def listen_two(target, arg):
+ result.append((target, arg))
+
+ t1 = Target()
+ event.listen(listen_one, "on_event_one", t1, propagate=True)
+ event.listen(listen_two, "on_event_two", t1)
+
+ t2 = Target()
+
+ t2.dispatch.update(t1.dispatch)
+
+ t2.dispatch.on_event_one(t2, 1)
+ t2.dispatch.on_event_two(t2, 2)
+ eq_(result, [(t2, 1)])
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file