diff options
author | jason kirtland <jek@discorporate.us> | 2016-08-22 14:20:42 -0700 |
---|---|---|
committer | jason kirtland <jek@discorporate.us> | 2016-08-22 14:20:42 -0700 |
commit | 7303d4bf1ab8a339a194d0d1935770bef43c3cca (patch) | |
tree | 1ecc59ac406e0f2de0989d7af174fdf031c42a6c | |
parent | 638cbae12f60965053f53b61191d2541fbf605b8 (diff) | |
download | blinker-7303d4bf1ab8a339a194d0d1935770bef43c3cca.tar.gz |
Added Signal.receiver_adapter, an just-in-time receiver decorator applied during :meth:`send`.
-rw-r--r-- | blinker/base.py | 25 | ||||
-rw-r--r-- | tests/test_signals.py | 22 |
2 files changed, 44 insertions, 3 deletions
diff --git a/blinker/base.py b/blinker/base.py index cc5880e..1b5b7dc 100644 --- a/blinker/base.py +++ b/blinker/base.py @@ -26,6 +26,8 @@ ANY = symbol('ANY') ANY.__doc__ = 'Token for "any sender".' ANY_ID = 0 +Unspecified = symbol('Unspecified') + class Signal(object): """A notification emitter.""" @@ -34,6 +36,11 @@ class Signal(object): #: without an additional import. ANY = ANY + #: If this callable is set, will be invoked with `(receiver, sender, + #: kwargs)` for each receiver during :meth:`send` instead of invoking + #: reciever functions directly. + receiver_adapter = None + @lazy_property def receiver_connected(self): """Emitted after each :meth:`connect`. @@ -70,14 +77,21 @@ class Signal(object): """ return Signal(doc="Emitted after a receiver disconnects.") - def __init__(self, doc=None): + def __init__(self, doc=None, receiver_adapter=Unspecified): """ :param doc: optional. If provided, will be assigned to the signal's __doc__ attribute. + :param receiver_adapter: optional callable. If provided, will be + invoked with `receiver, sender, kwargs` for each receiver during + :meth:`send` instead of invoking receivers functions directly. + + ... versionadded:: 1.5 """ if doc: self.__doc__ = doc + if receiver_adapter is not Unspecified: + self.receiver_adapter = receiver_adapter #: A mapping of connected receivers. #: #: The values of this mapping are not meaningful outside of the @@ -263,8 +277,13 @@ class Signal(object): if not self.receivers: return [] else: - return [(receiver, receiver(sender, **kwargs)) - for receiver in self.receivers_for(sender)] + if self.receiver_adapter is not None: + adapt = self.receiver_adapter + return [(receiver, adapt(receiver, sender, kwargs)) + for receiver in self.receivers_for(sender)] + else: + return [(receiver, receiver(sender, **kwargs)) + for receiver in self.receivers_for(sender)] def has_receivers_for(self, sender): """True if there is probably a receiver for *sender*. diff --git a/tests/test_signals.py b/tests/test_signals.py index a1172ed..2340bac 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -417,6 +417,28 @@ def test_decorated_receiver(): assert sig.receivers +def test_adapted_receiver(): + sentinel = [] + + def receiver(sender, **kw): + raise AssertionError + + def adapter(fn, sender, kw): + assert fn is receiver + sentinel.append(kw) + + sig_constructor = blinker.Signal(None, adapter) + sig_adhoc = blinker.Signal() + sig_adhoc.receiver_adapter = adapter + + for sig in (sig_constructor, sig_adhoc): + sig.connect(receiver) + del sentinel[:] + sig.send() + assert sentinel == [{}] + sig.disconnect(receiver) + + def test_no_double_send(): sentinel = [] def received(sender): |