pyee is a rough port of node.js’s EventEmitter. It’s missing a number of methods, but implements the basics. Unlike its namesake, it supports wrapping async functions/coroutines as seen in python 3.5+.


You can install this project into your environment of choice using pip:

pip install pyee

API Docs:

pyee supplies an EventEmitter object similar to the EventEmitter from Node.js. It supports both synchronous callbacks and asyncio coroutines.


In [1]: from pyee import EventEmitter

In [2]: ee = EventEmitter()

In [3]: @ee.on('event')
   ...: def event_handler():
   ...:     print('BANG BANG')

In [4]: ee.emit('event')

In [5]:
class pyee.EventEmitter(scheduler=<function ensure_future>, loop=None)

The EventEmitter class.

For interoperation with asyncio, one can specify the scheduler and the event loop. The scheduler defaults to asyncio.ensure_future, and the loop defaults to None. When used with the default scheduler, this will schedule the coroutine onto asyncio’s default loop.

This should also be compatible with recent versions of twisted by setting scheduler=twisted.internet.defer.ensureDeferred.

Most events are registered with EventEmitter via the on and once methods. However, pyee EventEmitters have two special events:

  • new_listener: Fires whenever a new listener is created. Listeners for this event do not fire upon their own creation.

  • error: When emitted raises an Exception by default, behavior can be overriden by attaching callback to the event.

    For example:

    def onError(message):
    ee.emit('error', Exception('something blew up'))

    For synchronous callbacks, exceptions are not handled for you— you must catch your own exceptions inside synchronous on handlers. However, when wrapping async functions, errors will be intercepted and emitted under the error event. This behavior for async functions is inconsistent with node.js, which unlike this package has no facilities for handling returned Promises from handlers.

emit(event, *args, **kwargs)

Emit event, passing *args and **kwargs to each attached function. Returns True if any functions are attached to event; otherwise returns False.


ee.emit('data', '00101001')

Assuming data is an attached function, this will call data('00101001')'.

For coroutine event handlers, calling emit is non-blocking. In other words, you do not have to await any results from emit, and the coroutine is scheduled in a fire-and-forget fashion.


Returns a list of all listeners registered to the event.

on(event, f=None)

Registers the function (or optionally an asyncio coroutine function) f to the event name event.

If f isn’t provided, this method returns a function that takes f as a callback; in other words, you can use this method as a decorator, like so:

def data_handler(data):

As mentioned, this method can also take an asyncio coroutine function:

async def data_handler(data)
    await do_async_thing(data)

This will automatically schedule the coroutine using the configured scheduling function (defaults to asyncio.ensure_future) and the configured event loop (defaults to asyncio.get_event_loop()).

In both the decorated and undecorated forms, the event handler is returned. The upshot of this is that you can call decorated handlers directly, as well as use them in remove_listener calls.

once(event, f=None)

The same as ee.on, except that the listener is automatically removed after being called.


Remove all listeners attached to event. If event is None, remove all listeners on all events.

remove_listener(event, f)

Removes the function f from event.