Eventlib-py
Eventlib-py is a small & simple event framework for Python that can be used to decouple your code.
Feature overview:
- Fast - Pre-computed event chains for fast event emission.
- Lightweight - No extra dependencies.
- Asynchronous - Full support for asynchronous event handlers and context managers.
- Priority Ordering - Control the order in which event handlers are called.
- Monitoring - Use context managers to monitor event processing.
- Compatible - Works with almost anything, use: dataclasses, Pydantic or attrs.
import asyncio
import dataclasses
import eventlib
@dataclasses.dataclass
class MyEvent(eventlib.BaseEvent):
value: str
@eventlib.subscribe()
async def on_my_event(event: MyEvent):
print(f"Received: {event.value}")
asyncio.run(MyEvent("Hello, world!").emit_async()) # Prints: "Received: Hello, world!"
Usage
Event Inheritance
import eventlib
class MyEvent(eventlib.BaseEvent):
pass
class SubEvent(MyEvent):
pass
@eventlib.subscribe()
def on_base_event(event: MyEvent):
print("Received event", event.__class__.__name__)
SubEvent().emit() # Prints: "Received event SubEvent"
Priority Ordering
import eventlib
class MyEvent(eventlib.BaseEvent):
pass
@eventlib.subscribe(priority=-1)
def first():
print("first")
@eventlib.subscribe() # default: priority = 0
def second():
print("second")
@eventlib.subscribe(priority=1)
def third():
print("third")
MyEvent().emit() # Prints: "first", "second", "third"
Context Managers
import contextlib
import eventlib
class MyEvent(eventlib.BaseEvent):
pass
@eventlib.subscribe(priority=-1000) # Ensure that this is called first
@contextlib.contextmanager
def monitor(event: MyEvent):
print("Event received")
try:
yield
finally:
print("Event processed")
@eventlib.subscribe()
def on_event(event: MyEvent):
print("on_event")
MyEvent().emit() # Prints: "Event received", "on_event", "Event processed"
Asyncio
import asyncio
import contextlib
import eventlib
class MyEvent(eventlib.BaseEvent):
pass
@eventlib.subscribe(priority=-1000) # Ensure that this is called first
@contextlib.asynccontextmanager
async def monitor(event: MyEvent):
print("Event received")
try:
yield
finally:
print("Event processed")
@eventlib.subscribe()
async def async_on_event(event: MyEvent):
print("async_on_event")
@eventlib.subscribe()
def on_event(event: MyEvent):
print("on_event")
asyncio.run(MyEvent().emit_async()) # Prints: "Event received", "async_on_event", "on_event", "Event processed"
Benchmarks
The benchmark directory contains code to measure the performance of the eventlib-py library and compare it with a hard-coded reference implementation in Python.
Benchmark case_all
The following table shows the overhead of the eventlib-py library in the case_all benchmark. It's a mixed benchmark with all kinds of sync & async event handlers and context managers.
| Quantile | Hardcoded Time/Event | EventLib Time/Event | Overhead per Call | EventLib Setup |
|---|---|---|---|---|
| 0.50 | 42.289μs | 45.373μs | +7% | 135.125μs |
| 0.90 | 43.560μs | 46.809μs | +10% | 143.000μs |
| 0.99 | 46.658μs | 50.048μs | +15% | 260.393μs |
The overhead per call is the additional time that is needed to call the event handlers introduced by the eventlib-py library. The setup time is the additional nonrecurring overhead for subscribing the event handlers in the event system. It shows that in the worst case a 15% overhead per call is introduced. The expected median overhead is around 7% versus hard-coded event handling.
Development
Use poetry to setup the development environment.
poetry install --with=dev
poetry shell
Run the auto-formatter, checks and linter:
black .
isort .
mypy .
pylint .
Run the tests with coverage:
pytest --cov
Contributing
Contributions are welcome.
Please follow the commit convention https://www.conventionalcommits.org/en/v1.0.0/.
License
Dual-licensed under the terms of either the Apache License 2.0 or the MIT license.
SPDX-License-Identifier: (Apache-2.0 OR MIT)
Release files for eventlib-py 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| eventlib_py-1.2.0.tar.gz | 16.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| eventlib_py-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.8 kB
Release files / eventlib_py-1.2.0.tar.gz
| Download URL | eventlib_py-1.2.0.tar.gz |
|---|---|
| Size | 16.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e8c6222c6733dcc4c406e841e24eccf0e50786d7be0ff4ab9e42404d0f3bf011
|
|
BLAKE2b-256 checksum How to use checksums |
f893d099cf6dd5a7407d67d8f710ae09e57aa1e7f70229094df48aac3b1f5c52
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.
Transparency logRelease files / eventlib_py-1.2.0-py3-none-any.whl
| Download URL | eventlib_py-1.2.0-py3-none-any.whl |
|---|---|
| Size | 14.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
af13430f8e7f6243a3393297b459405a86d6e339efaee224998b7fa311c419e1
|
|
BLAKE2b-256 checksum How to use checksums |
6feb658ca7ead780c80fcf24aa08964283a841928b5e69b21cbae2ff8b49882f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.
Transparency log