Skip to main content

Python Event System (PyESys)

A Python-native event system with thread-safe, type-safe event handling and first-class async support.

PyESys brings clean, per-instance event handling to Python using familiar patterns like property descriptors and operator overloading. Perfect for real-time systems, simulations, and any application requiring robust event-driven architecture.

from pyesys import event

class Button:
    @event
    def on_click(self):
        """Click event signature"""
    
    @on_click.emitter
    def click(self):
        print("Button clicked!")

# Each instance gets its own events
btn = Button()
btn.on_click += lambda: print("Handler executed!")
btn.click()
# Output: Button clicked!
#         Handler executed!

Why PyESys?

  • Per-Instance Events: No global registries or string-based keys. Each object manages its own events independently.

  • Type Safety: Runtime signature validation catches handler mismatches early.

  • Async-Ready: Mix sync and async handlers seamlessly with automatic thread pool handling.

  • Pythonic: Familiar @event decorator syntax inspired by @property, plus +=/-= operators.

  • Memory Safe: Built-in weak references prevent common memory leak patterns.

  • Thread Safe: Safe concurrent event emission across multiple threads.

Quick Start

Installation

pip install pyesys

Requires Python 3.12+. Zero dependencies.

Basic Usage

from pyesys import create_event

# Create event with signature validation
event, listener = create_event(example=lambda msg: None)

def log_message(msg: str):
    print(f"[LOG] {msg}")

# Subscribe and emit
listener += log_message
event.emit("Hello PyESys!")
# Output: [LOG] Hello PyESys!

Class-Based Events

from pyesys import event

class FileProcessor:
    @event
    def on_progress(self, filename: str, percent: float):
        """Progress update event"""
    
    @on_progress.emitter
    def _update_progress(self, filename: str, percent: float):
        pass  # Event automatically emitted
    
    def process(self, filename: str):
        for i in range(0, 101, 25):
            self._update_progress(filename, i)

# Each processor has independent events
processor = FileProcessor()
processor.on_progress += lambda f, p: print(f"{f}: {p}% complete")

processor.process("data.txt")
# Output: data.txt: 0% complete
#         data.txt: 25% complete
#         ...

Advanced Features

Event Chaining

Create processing pipelines by chaining events between objects:

class DataProcessor:
    @event
    def on_processed(self, data: dict):
        pass
    
    @on_processed.emitter
    def process(self, data: dict):
        # Transform data
        return {"processed": True, **data}

class DataValidator:
    def validate(self, data: dict):
        print(f"Validating: {data}")

processor = DataProcessor()
validator = DataValidator()

# Chain processors
processor.on_processed += validator.validate
processor.process({"id": 123})

Async Support

Mix synchronous and asynchronous handlers effortlessly:

import asyncio

async def async_handler(data):
    await asyncio.sleep(0.1)
    print(f"Async: {data}")

def sync_handler(data):
    print(f"Sync: {data}")

listener += [sync_handler, async_handler]
await event.emit_async("mixed-handlers")
# Both handlers run concurrently

Bulk Operations

Efficiently manage multiple handlers:

# Bulk subscribe
listener += [handler1, handler2, handler3]

# Bulk unsubscribe  
listener -= {handler1, handler2}

# Introspection
print(f"Active handlers: {listener.handler_count()}")

Production Error Handling

def error_handler(exception, handler_func):
    logger.error(f"Handler {handler_func.__name__} failed: {exception}")

event, listener = create_event(
    example=lambda x: None,
    error_handler=error_handler
)
# Failing handlers won't crash the system

Real-World Use Cases

  • Real-time Systems: React to sensor inputs and control signals
  • Simulation Frameworks: Decouple models from visualization/control
  • Plugin Architectures: Extend applications safely with event hooks
  • UI/Backend Integration: Bridge sync and async worlds seamlessly
  • Testable Systems: Replace complex callbacks with observable events

Documentation

License

MIT License - see LICENSE file.


PyESys - Pythonic events for modern applications 🐍✨

Release files for pyesys 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyesys 0.2.1
File Size Uploaded
pyesys-0.2.1.tar.gz 41.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyesys 0.2.1
File Interpreter ABI Platform
pyesys-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 56.4 kB

Release files / pyesys-0.2.1.tar.gz

Download URL pyesys-0.2.1.tar.gz
Size 41.8 kB
Tags Source
SHA-256 checksum
How to use checksums
6dcc076052da1ab2d8ba70f176b77273fb1eb4f0c73bac99508ff48c6b73c949
BLAKE2b-256 checksum
How to use checksums
3d11fb2b68c93ff21a85a13beaeb49678f58ef11f46138aa28cb93ec7ef007ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via python-requests/2.32.3

Release files / pyesys-0.2.1-py3-none-any.whl

Download URL pyesys-0.2.1-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dbedde5f4029e7cfafc2f4f90458b59e77bbe9edb9a812793e3186655acb8f2c
BLAKE2b-256 checksum
How to use checksums
a0d2875b2330a7668e1eda6f10fcde5691f6e8e2c8a0b046c6a93d1602c4c6ae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via python-requests/2.32.3

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page