Source code for adsorb.adsorb
# -*- coding: utf-8 -*-
from sys import exc_info
from collections import defaultdict
[docs]class Event(object):
"""
Collects responses to the event. Attributes:
* :attr:`name`: Name of the event
* :attr:`context`: Context for event, provided by caller
* :attr:`data`: Additional data provided by caller
* :attr:`results`: Dictionary of results from each listener
* :attr:`exceptions`: Dictionary of ``(exception, value)`` from failed listeners
Event objects are automatically created by :meth:`Adsorber.raiseEvent` and passed
as the sole parameter to each listener.
"""
def __init__(self, adsorber, name, context, **kw):
self.adsorber = adsorber
self.name = name
self.context = context
self.data = kw
self.results = {}
self.exceptions = {}
def __repr__(self):
return u"<Event '%s'> on %s" % (self.name, repr(self.context))
[docs] def call(self):
"""
Call all listeners for this event and collect their output.
"""
events = self.adsorber._getEvents(self.name)
for listenerid in events:
try:
self.results[listenerid] = events[listenerid](self)
except:
self.exceptions[listenerid] = exc_info()[:2] # Save exception and value
[docs]class Adsorber(object):
"""
Container for events and listeners. Typically used as a singleton instance
for the entire application.
"""
def __init__(self):
self.__events = defaultdict(dict)
def _getEvents(self, name):
"""Return all events for given event name."""
return self.__events[name]
[docs] def addListener(self, eventname, listenerid, listener):
"""
Add a listener to the named event. Listeners are passed an instance of
:class:`Event` as the sole parameter. The return value from the listener
is collected in the event object's :attr:`results` attribute.
"""
self.__events[eventname][listenerid] = listener
[docs] def removeListener(self, eventname, listenerid):
"""
Remove a listener on an event.
"""
del self.__events[eventname][listenerid]
[docs] def removeEvent(self, eventname, confirm=False):
"""
Remove all listeners on an event.
"""
if confirm:
del self.__events[eventname]
[docs] def raiseEvent(self, eventname, context, **kw):
"""
Raise an event. All listeners are called and their return values or
exceptions are collected before execution resumes with the caller.
Caller must provide a mandatory ``context`` and optional named attributes
as data for the event.
"""
e = Event(self, eventname, context, **kw)
e.call()
return e
[docs] def listener(self, eventname):
"""
Decorator for event listeners to automate the call to :meth:`addListener`.
Usage::
@adsorb_instance.listener("event-name")
def your_listener(event):
...
@adsorb_instance.listener(("event1", event2")):
def your_listener(event):
...
A listenerid for the listener is automatically constructed from the
module and function names. This decorator can only be used with module
top-level functions. For class methods and nested functions, call
:meth:`addListener` at run-time.
"""
def decorator(f):
listenerid = '%s.%s' % (f.__module__, f.__name__)
if isinstance(eventname, (tuple, list)):
for e in eventname:
self.addListener(e, listenerid, f)
else:
self.addListener(eventname, listenerid, f)
return f
return decorator