pyee is a rough port of node.js’s EventEmitter. Unlike its namesake, it includes a number of subclasses useful for implementing async and threaded programming in python, such as async/await as seen in python 3.5+.
You can install this project into your environment of choice using
pip install pyee
pyee supplies a
EventEmitter class that is similar to the
EventEmitter class from Node.js. In addition, it supplies the subclasses
for supporting async and threaded execution with asyncio, twisted, and
concurrent.futures Executors respectively, as supported by the environment.
In : from pyee import EventEmitter In : ee = EventEmitter() In : @ee.on('event') ...: def event_handler(): ...: print('BANG BANG') ...: In : ee.emit('event') BANG BANG In :
An event emitter class which can run asyncio coroutines in addition to synchronous blocking functions. For example:
@ee.on('event') async def async_handler(*args, **kwargs): await returns_a_future()
On emit, the event emitter will automatically schedule the coroutine using
asyncio.ensure_futureand the configured event loop (defaults to
Unlike the case with the BaseEventEmitter, all exceptions raised by event handlers are automatically emitted on the
errorevent. This is important for asyncio coroutines specifically but is also handled for synchronous functions for consistency.
loopis specified, the supplied event loop will be used when scheduling work with
ensure_future. Otherwise, the default asyncio event loop is used.
For asyncio 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.
An event emitter class which can run twisted coroutines and handle returned Deferreds, in addition to synchronous blocking functions. For example:
@ee.on('event') @inlineCallbacks def async_handler(*args, **kwargs): yield returns_a_deferred()
@ee.on('event') async def async_handler(*args, **kwargs): await returns_a_deferred()
When async handlers fail, Failures are first emitted on the
failureevent. If there are no
failurehandlers, the Failure’s associated exception is then emitted on the
errorevent. If there are no
errorhandlers, the exception is raised. For consistency, when handlers raise errors synchronously, they’re captured, wrapped in a Failure and treated as an async failure. This is unlike the behavior of BaseEventEmitter, which have no special error handling.
For twisted 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.
Similar behavior occurs for “sync” functions which return Deferreds.
An event emitter class which runs handlers in a
By default, this class creates a default
ThreadPoolExecutor, but a custom executor may also be passed in explicitly to, for instance, use a
This class runs all emitted events on the configured executor. Errors captured by the resulting Future are automatically emitted on the
errorevent. This is unlike the BaseEventEmitter, which have no error handling.
The underlying executor may be shut down by calling the
shutdownmethod. Alternately you can treat the event emitter as a context manager:
with ExecutorEventEmitter() as ee: # Underlying executor open @ee.on('data') def handler(data): print(data) ee.emit('event') # Underlying executor closed
Since the function call is scheduled on an executor, emit is always non-blocking.
No effort is made to ensure thread safety, beyond using an executor.
shutdownon the internal executor.
An event emitter class which can run trio tasks in a trio nursery.
By default, this class will lazily create both a nursery manager (the object returned from
trio.open_nursery()and a nursery (the object yielded by using the nursery manager as an async context manager). It is also possible to supply an existing nursery manager via the
managerargument, or an existing nursery via the
Instances of TrioEventEmitter are themselves async context managers, so that they may manage the lifecycle of the underlying trio nursery. For example, typical usage of this library may look something like this:
async with TrioEventEmitter() as ee: # Underlying nursery is instantiated and ready to go @ee.on('data') async def handler(data): print(data) ee.emit('event') # Underlying nursery and manager have been cleaned up
Unlike the case with the BaseEventEmitter, all exceptions raised by event handlers are automatically emitted on the
errorevent. This is important for trio coroutines specifically but is also handled for synchronous functions for consistency.
For trio coroutine event handlers, calling emit is non-blocking. In other words, you should not attempt to await emit; the coroutine is scheduled in a fire-and-forget fashion.
Returns an async contextmanager which manages the underlying nursery to the EventEmitter. The
TrioEventEmitter’s async context management methods are implemented using this function, but it may also be used directly for clarity.
The base event emitter class. All other event emitters inherit from this class.
Most events are registered with an emitter via the
oncemethods, and fired with the
emitmethod. However, pyee event emitters 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.
@ee.on('error') def on_error(message): logging.err(message) ee.emit('error', Exception('something blew up'))
All callbacks are handled in a synchronous, blocking manner. As in node.js, raised exceptions are not automatically handled for you—you must catch your own exceptions, and treat them accordingly.
emit(event, *args, **kwargs)¶
**kwargsto each attached function. Returns
Trueif any functions are attached to
event; otherwise returns
datais an attached function, this will call
Returns a list of all listeners registered to the
Registers the function
fto the event name
fisn’t provided, this method returns a function that takes
fas a callback; in other words, you can use this method as a decorator, like so:
@ee.on('data') def data_handler(data): print(data)
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.
The same as
ee.on, except that the listener is automatically removed after being called.
Remove all listeners attached to
None, remove all listeners on all events.
Removes the function
An exception internal to pyee.
uplift(cls, underlying, error_handling='new', proxy_new_listener='forward', *args, **kwargs)¶
A helper to create instances of an event emitter
clsthat inherits event behavior from an
underlyingevent emitter instance.
This is mostly helpful if you have a simple underlying event emitter that you don’t have direct control over, but you want to use that event emitter in a new context - for example, you may want to
BaseEventEmittersupplied by a third party library into an
AsyncIOEventEmitterso that you may register async event handlers in your
asyncioapp but still be able to receive events from the underlying event emitter and call the underlying event emitter’s existing handlers. This trick will also often work for a deprecated
upliftinstantiates a new instance of
cls, passing along any unrecognized arguments, and overwrites the
emitmethod on the
underlyingevent emitter to also emit events on the new event emitter and vice versa. In both cases, they return whether the
emitmethod was handled by either emitter. Execution order prefers the event emitter on which
upliftalso adds an
unwrapmethod to both instances, either of which will unwrap both
emitmethods when called.
error_handlingflag can be configured to control what happens to unhandled errors:
‘new’: Error handling for the new event emitter is always used and the underlying library’s non-event-based error handling is inert.
‘underlying’: Error handling on the underlying event emitter is always used and the new event emitter can not implement non-event-based error handling.
‘neither’: Error handling for the new event emitter is used if the handler was registered on the new event emitter, and vice versa.
Tuning this option can be useful depending on how the underlying event emitter does error handling. The default is ‘new’.
proxy_new_listeneroption can be configured to control how
new_listenerevents are treated:
new_listenerevents are propagated from the underlying
new_listenerevents are propagated as with other events.
new_listenerevents are only fired on their respective event emitters. event emitter to the new event emitter but not vice versa.
new_listenerevents are propagated from the new event emitter to the underlying event emitter, but not vice versa.
Tuning this option can be useful depending on how the
new_listenerevent is used by the underlying event emitter, if at all. The default is ‘forward’, since
underlyingmay not know how to handle certain handlers, such as asyncio coroutines.
Each event emitter tracks its own internal table of handlers.
listenersall work independently. This means you will have to remember which event emitter an event handler was added to!
Note that both the new event emitter returned by
clsand the underlying event emitter should inherit from
BaseEventEmitter, or at least implement the interface for the undocumented
2021/8/14 Version 8.2.2¶
Correct version in docs
2021/8/14 Version 8.2.1¶
Add .readthedocs.yaml file
Remove vcversioner dependency from docs build
2021/8/14 Version 8.2.0¶
Remove test_requires and setup_requires directives from setup.py (closing #82)
Remove vcversioner from dependencies
Streamline requirements.txt and environment.yml files
Update and extend CONTRIBUTING.rst
CI with GitHub Actions instead of Travis (closing #56)
Format all code with black
Switch default branch to
Add the CHANGELOG to Sphinx docs (closing #51)
Updated copyright information
2020/10/08 Version 8.1.0¶
Improve thread safety in base EventEmitter
Documentation fix in ExecutorEventEmitter
2020/09/20 Version 8.0.1¶
Update README to reflect new API
2020/09/20 Version 8.0.0¶
Drop support for Python 2.7
Remove CompatEventEmitter and rename BaseEventEmitter to EventEmitter
Create an alias for BaseEventEmitter with a deprecation warning
2020/09/20 Version 7.0.4¶
setup_requires vs tests_require now correct
tests_require updated to pass in tox
3.7 testing removed from tox
2.7 testing removed from Travis
2020/09/04 Version 7.0.3¶
Tag license as MIT in setup.py
Update requirements and environment to pip -e the package
2020/05/12 Version 7.0.2¶
Support Python 3.8 by attempting to import TimeoutError from
Add LICENSE to package manifest
Add trio testing to tox
Add Python 3.8 to tox
Fix Python 2.7 in tox
2020/01/30 Version 7.0.1¶
Some tweaks to the docs
2020/01/30 Version 7.0.0¶
TrioEventEmitterclass for intended use with trio
AsyncIOEventEmitternow correctly handles cancellations
Add a new experimental
pyee.upliftAPI for adding new functionality to existing event emitters
2019/04/11 Version 6.0.0¶
BaseEventEmitterclass which is entirely synchronous and intended for simple use and for subclassing
AsyncIOEventEmitterclass for intended use with asyncio
TwistedEventEmitterclass for intended use with twisted
ExecutorEventEmitterclass which runs events in an executor
EventEmitter(use one of the new classes)
2017/11/18 Version 5.0.0¶
CHANGELOG.md reformatted to CHANGELOG.rst
The listeners method no longer returns the raw list of listeners, and instead returns a list of unwrapped listeners; This means that mutating listeners on the EventEmitter by mutating the list returned by this method isn’t possible anymore, and that for once handlers this method returns the unwrapped handler rather than the wrapped handler
once API now returns the unwrapped handler in both decorator and non-decorator cases
Possible to remove once handlers with unwrapped handlers
Internally, listeners are now stored on a OrderedDict rather than a list
Minor stylistic tweaks to make code more pythonic
2017/11/17 Version 4.0.1¶
Fix bug in setup.py; Now publishable
2017/11/17 Version 4.0.0¶
Coroutines now work with .once
Wrapped listener is removed prior to hook execution rather than after for synchronous .once handlers
2017/02/12 Version 3.0.3¶
Add universal wheel
2017/02/10 Version 3.0.2¶
EventEmitter now inherits from object
2016/10/02 Version 3.0.1¶
Fixes/Updates to pyee docs
Uses vcversioner for managing version information
2016/10/02 Version 3.0.0¶
Errors resulting from async functions are now proxied to the “error” event, rather than being lost into the aether.
2016/10/01 Version 2.0.3¶
Fix setup.py broken in python 2.7
Add link to CHANGELOG in README
2016/10/01 Version 2.0.2¶
Fix RST render warnings in README
2016/10/01 Version 2.0.1¶
Add README contents as long_description inside setup.py
2016/10/01 Version 2.0.0¶
Drop support for pythons 3.2, 3.3 and 3.4 (support 2.7 and 3.5)
Use pytest instead of nose
Removed Event_emitter alias
Code passes flake8
Use setuptools (no support for users without setuptools)
Reogranized docs, hosted on readthedocs.org
Support for scheduling coroutine functions passed to @ee.on
2016/02/15 Version 1.0.2¶
Make copy of event handlers array before iterating on emit
2015/09/21 Version 1.0.1¶
Change URLs to reference jfhbrook
2015/09/20 Version 1.0.0¶
Decorators return original function for on and once
Explicit python 3 support
Addition of legit license file
Addition of CHANGELOG.md
Now properly using semver