Module fast_transformers.events.event_dispatcher

Expand source code
#
# Copyright (c) 2020 Idiap Research Institute, http://www.idiap.ch/
# Written by Angelos Katharopoulos <angelos.katharopoulos@idiap.ch>
#

from collections import OrderedDict

from .event import Event
from .filters import event_class


class EventDispatcher(object):
    """An EventDispatcher is a simple way to implement an observer pattern for
    loose coupling of components. In our case it is used so that the internals
    of large neural networks can communicate with the outside world in an
    agnostic and efficient way.

    Example usage
    -------------

        from fast_transformers.events import EventDispatcher, AttentionEvent
        from fast_transformers.events.filters import \
            layer_name_contains

        def attention_event_handler(event):
            print(event.attention_matrix)

        ed = EventDispatcher()
        ed.listen(AttentionEvent, attention_event_handler)
        ed.listen(
            AttentionEvent & layer_name_contains("layers.12"),
            attention_event_handler
        )
    """
    _dispatchers = {}

    def __init__(self):
        self._listeners = OrderedDict()

    def listen(self, event_filter, event_handler):
        """Add an event handler for the events that pass the event filter.

        Arguments
        ---------
            event_filter: callable or Event class to define for which events
                          this handler will be called
            event_handler: callable that accepts an instance of Event
        """
        if isinstance(event_filter, type) and issubclass(event_filter, Event):
            event_filter = event_class(event_filter)

        self._listeners[event_handler] = event_filter

    def remove(self, event_handler):
        """Remove the event_handler from the listeners so that no more events
        are dispatched to this handler."""
        self._listeners.pop(event_handler, None)

    def clear(self):
        """Remove all listeners from the event dispatcher."""
        self._listeners.clear()

    def dispatch(self, event):
        """Dispatch an event to the listeners.

        Arguments
        ---------
            event: Event instance
        """
        for event_handler, event_filter in self._listeners.items():
            if event_filter(event):
                event_handler(event)

    @classmethod
    def get(cls, key=""):
        """Factory method for creating global event dispatchers for loosely
        coupling parts of a larger codebase.

        Since global objects are a complete antipattern, we suggest that this
        is only used to set a default value for an event dispatcher passed as
        an argument.

        Argument
        --------
            key: A key to uniquely identify a dispatcher or an instance of a
                 dispatcher to be returned as is
        """
        if isinstance(key, cls):
            return key
        if key not in cls._dispatchers:
            cls._dispatchers[key] = cls()
        return cls._dispatchers[key]

Classes

class EventDispatcher

An EventDispatcher is a simple way to implement an observer pattern for loose coupling of components. In our case it is used so that the internals of large neural networks can communicate with the outside world in an agnostic and efficient way.

Example Usage

from fast_transformers.events import EventDispatcher, AttentionEvent
from fast_transformers.events.filters import             layer_name_contains

def attention_event_handler(event):
    print(event.attention_matrix)

ed = EventDispatcher()
ed.listen(AttentionEvent, attention_event_handler)
ed.listen(
    AttentionEvent & layer_name_contains("layers.12"),
    attention_event_handler
)
Expand source code
class EventDispatcher(object):
    """An EventDispatcher is a simple way to implement an observer pattern for
    loose coupling of components. In our case it is used so that the internals
    of large neural networks can communicate with the outside world in an
    agnostic and efficient way.

    Example usage
    -------------

        from fast_transformers.events import EventDispatcher, AttentionEvent
        from fast_transformers.events.filters import \
            layer_name_contains

        def attention_event_handler(event):
            print(event.attention_matrix)

        ed = EventDispatcher()
        ed.listen(AttentionEvent, attention_event_handler)
        ed.listen(
            AttentionEvent & layer_name_contains("layers.12"),
            attention_event_handler
        )
    """
    _dispatchers = {}

    def __init__(self):
        self._listeners = OrderedDict()

    def listen(self, event_filter, event_handler):
        """Add an event handler for the events that pass the event filter.

        Arguments
        ---------
            event_filter: callable or Event class to define for which events
                          this handler will be called
            event_handler: callable that accepts an instance of Event
        """
        if isinstance(event_filter, type) and issubclass(event_filter, Event):
            event_filter = event_class(event_filter)

        self._listeners[event_handler] = event_filter

    def remove(self, event_handler):
        """Remove the event_handler from the listeners so that no more events
        are dispatched to this handler."""
        self._listeners.pop(event_handler, None)

    def clear(self):
        """Remove all listeners from the event dispatcher."""
        self._listeners.clear()

    def dispatch(self, event):
        """Dispatch an event to the listeners.

        Arguments
        ---------
            event: Event instance
        """
        for event_handler, event_filter in self._listeners.items():
            if event_filter(event):
                event_handler(event)

    @classmethod
    def get(cls, key=""):
        """Factory method for creating global event dispatchers for loosely
        coupling parts of a larger codebase.

        Since global objects are a complete antipattern, we suggest that this
        is only used to set a default value for an event dispatcher passed as
        an argument.

        Argument
        --------
            key: A key to uniquely identify a dispatcher or an instance of a
                 dispatcher to be returned as is
        """
        if isinstance(key, cls):
            return key
        if key not in cls._dispatchers:
            cls._dispatchers[key] = cls()
        return cls._dispatchers[key]

Static methods

def get(key='')

Factory method for creating global event dispatchers for loosely coupling parts of a larger codebase.

Since global objects are a complete antipattern, we suggest that this is only used to set a default value for an event dispatcher passed as an argument.

Argument

key: A key to uniquely identify a dispatcher or an instance of a
     dispatcher to be returned as is
Expand source code
@classmethod
def get(cls, key=""):
    """Factory method for creating global event dispatchers for loosely
    coupling parts of a larger codebase.

    Since global objects are a complete antipattern, we suggest that this
    is only used to set a default value for an event dispatcher passed as
    an argument.

    Argument
    --------
        key: A key to uniquely identify a dispatcher or an instance of a
             dispatcher to be returned as is
    """
    if isinstance(key, cls):
        return key
    if key not in cls._dispatchers:
        cls._dispatchers[key] = cls()
    return cls._dispatchers[key]

Methods

def clear(self)

Remove all listeners from the event dispatcher.

Expand source code
def clear(self):
    """Remove all listeners from the event dispatcher."""
    self._listeners.clear()
def dispatch(self, event)

Dispatch an event to the listeners.

Arguments

event: Event instance
Expand source code
def dispatch(self, event):
    """Dispatch an event to the listeners.

    Arguments
    ---------
        event: Event instance
    """
    for event_handler, event_filter in self._listeners.items():
        if event_filter(event):
            event_handler(event)
def listen(self, event_filter, event_handler)

Add an event handler for the events that pass the event filter.

Arguments

event_filter: callable or Event class to define for which events
              this handler will be called
event_handler: callable that accepts an instance of Event
Expand source code
def listen(self, event_filter, event_handler):
    """Add an event handler for the events that pass the event filter.

    Arguments
    ---------
        event_filter: callable or Event class to define for which events
                      this handler will be called
        event_handler: callable that accepts an instance of Event
    """
    if isinstance(event_filter, type) and issubclass(event_filter, Event):
        event_filter = event_class(event_filter)

    self._listeners[event_handler] = event_filter
def remove(self, event_handler)

Remove the event_handler from the listeners so that no more events are dispatched to this handler.

Expand source code
def remove(self, event_handler):
    """Remove the event_handler from the listeners so that no more events
    are dispatched to this handler."""
    self._listeners.pop(event_handler, None)