예제 #1
0
class EventService(Service):
    def __init__(self, env):
        """event service"""
        super(EventService, self).__init__(env)
        self._channel = Signal('event_channel')

    def subscribe(self, func, event_type=None ):
        '''
        :param func: def func(event_type, **kwarg):
                        pass
        :param event_filter: option
        :return:
        '''
        # sender = event_type or ANY
        # weak = True
        # if isinstance(event_type, basestring):
        #     weak = False
        # self._channel.connect(func, sender, weak)
        sender = event_type or ANY
        self._channel.connect(func, sender)

    def unsubscribe(self, func):
        self._channel.disconnect(func)

    def publish(self, event_type, **kwarg):
        self._channel.send(event_type, **kwarg)
예제 #2
0
    python exapmle05.py disconnect  # running signal testing with disconnect one callback
                                    # and you can see only one signal callback called

Notice:
    **disconnect** can disconnect receiver from signal’s events.
"""
import sys

from blinker import Signal

signal = Signal('disconnect_signal')


@signal.connect_via(Signal.ANY)
def receive_data(sender, **kw):
    print("Caught strong signal from : {}, data: {}".format(sender, kw))
    return "test"


@signal.connect_via(Signal.ANY)
def receive_data2(sender, **kw):
    print("Caught signal2 from : {}, data: {}".format(sender, kw))
    return "received2"


if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == 'disconnect':
        signal.disconnect(receive_data, Signal.ANY)
    result = signal.send('anonymous', abc=123)
    print(result)
예제 #3
0
class SignalEmitter:
    """Class that allows other callables to connect to it listen for signals.

    Callables can be attached to a SignalEmitter via SignalEmitter.connect.
    If the SignalEmitter calls SignalEmitter.signal.send(*args, **kwargs), any
    callables are called with the respective args and kwargs.

    Args:
        initialize_signal: instantiate a blnker.Signal object. If set to False,
            self.Signal needs to be set later on. This could be useful when you
            want a single Signal that is shared by all class instances.
        multiple_senders: Allow to be connected to multiple senders.
            If False, when connected to a second SignalEmitter, the connection
            to the previous SignalEmitter is disconnected

    Note:
        The SignalEmitter has protection against infinite recursions resulting
        from signal emitters calling each other. This is done by keeping track
        of the signal chain. However, it does not protect against infinite
        recursions from signals sent from objects that are not signal emitters.
    """
    # Signal used for connecting to parameter via SignalEmitter.connect method
    signal = None

    def __init__(self,
                 initialize_signal: bool = True,
                 multiple_senders: bool = True):
        self._signal_chain = []
        if initialize_signal:
            self.signal = Signal()

        self._signal_modifiers = {'offset': None, 'scale': None}

        # By default self is not connected to any other SignalEmitter
        self.sender = None

        self.multiple_senders = multiple_senders

    def connect(self,
                receiver,
                update=False,
                offset: float = None,
                scale: float = None):
        """Connect a receiver, which can be another SignalEmitter.

        If a SignalEmitter is passed, the __call__ method is invoked.

        Args:
            receiver: Receiver to be connected to this SignalEmitter's signal.
            offset: Optional offset to apply to emitted value
            scale: Optional scale to apply to emitted value

        Note:
            If offset or scale is provided, the emitted value should be a number.
            If an emitted signal contains 'value' as kwarg, this will be
            modified. Otherwise the first arg (sender) will be modified.
        """
        if self.signal is None:
            self.signal = Signal()

        if isinstance(receiver, SignalEmitter):
            # Remove any previous sender if multiple_senders is False
            if not receiver.multiple_senders and receiver.sender is not None:
                receiver.sender.disconnect(receiver)

            receiver._signal_modifiers['offset'] = offset
            receiver._signal_modifiers['scale'] = scale
            self.signal.connect(receiver._signal_call)
            receiver.sender = self

        else:
            self.signal.connect(receiver)

        if update:
            # Update callable with current value
            value = self()
            if scale is not None:
                if callable(scale):
                    scale = scale(self)
                value *= scale
            if offset is not None:
                if callable(offset):
                    offset = offset(self)
                value += offset

            receiver(value)

    def disconnect(self, callable):
        """disconnect a callable from a SignalEmitter.

        Note:
            Does not raise error if callable is not connected in the first place
            """
        if isinstance(callable, SignalEmitter):
            callable = callable._signal_call

        if getattr(self, 'signal', None) is not None:
            for receiver_ref in list(self.signal.receivers.values()):
                receiver = receiver_ref()
                if receiver == callable:
                    self.signal.disconnect(callable)

    def _signal_call(self, sender, *args, **kwargs):
        """Method that is called instead of standard __call__ for SignalEmitters

        This method ensures that the actual __call__ is only invoked if this has
        not previously been done during the signal chain.
        """
        if self not in self._signal_chain:
            value = kwargs.get('value', sender)

            # If any modifier is set,
            if self._signal_modifiers['scale'] is not None:
                scale = self._signal_modifiers['scale']
                if callable(scale):
                    scale = scale(self.sender)
                value *= scale

            if self._signal_modifiers['offset'] is not None:
                offset = self._signal_modifiers['offset']
                if callable(offset):
                    offset = offset(self.sender)
                value += offset

            if 'value' in kwargs:
                kwargs['value'] = value
            else:
                sender = value
            return self(sender,
                        *args,
                        signal_chain=self._signal_chain,
                        **kwargs)