Skip to main content

A lightweight, modular event system for Python applications with plugin architecture support.

Project description

Moduvent - Python Event-Driven Framework

zread

A lightweight, modular event system for Python applications with plugin architecture support.

Features

🎯 Simple and intuitive event subscription and emission

🧩 Dynamic module loading system for extensibility

📝 Comprehensive logging with Loguru integration

🏗️ Class-based event handlers with metaclass support

🔧 Type annotations throughout for better development experience

Installation

pip install moduvent

Quick Start

Everything below can be imported from the moduvent package.

Define a custom event

We say an event holds data that is relevant to a certain type of event. For example, a UserLoggedIn event might hold the user ID and timestamp of the login.

class UserLoggedIn(Event):
    def __init__(self, user_id, timestamp):
        self.user_id = user_id
        self.timestamp = timestamp

Subscribe your events

Once you finished defining your events, you can subscribe some functions (both bound methods and unbound functions) to them using the subscribe decorator for unbound functions and subscribe_method for bound methods.

# Unbound function
@subscribe(UserLoggedIn)
def handle_user_login(event):
    """Once a UserLoggedIn event is emitted, this function will be called."""
    # use your event data!
    print(f"User {event.user_id} logged in at {event.timestamp}")

# Bound method
class UserManager(EventAwareBase):
    @subscribe_method(UserLoggedIn)
    def on_user_login(self, event):
        """Once a UserLoggedIn event is emitted, this method will be called."""
        # use your event data here!
        print(f"UserManager noticed login: {event.user_id}")

    # !!IMPORTANT:
    # When you are subscribing a static or class method, you should always KNOW WHAT YOU ARE DOING since the subscription will be registered every time the class is instantiated.
    # This in most cases is not what you want.
    @subscribe_method(UserLoggedIn)
    @staticmethod
    def handle_user_login(event):
        """Static method can also be subscribed to events."""
        # use your event data here!
        pass

    @subscribe_method(UserLoggedIn)
    @classmethod
    def handle_user_login_cls(cls, event):
        """Class method can also be subscribed to events."""
        # use your event data here!
        pass

# Or also subscribe it by hand
register(handle_user_login, UserLoggedIn)

The regirstration of a bound method is realized by inherting from the EventAwareBase class, which provides a metaclass that automatically registers the class method as an event handler when the class is instantiated.

Emit events

if __name__ == "__main__":
    emit(UserLoggedIn(user_id=123, timestamp="2023-01-01 12:00:00"))
    # or anywhere else in your code

Unsubscribe events

You can unsubscribe subscriptions in many ways:

# Unsubscribe a function from an event type
unsubscribe(handle_user_login, UserLoggedIn)
# or
unsubscribe(a_user_manager_instance.handle_user_login, UserLoggedIn)

# Unsubscribe a function from all event types
unsubscribe(handle_user_login)

# Unsubscribe all functions from an event type
unsubscribe(UserLoggedIn)

Module System

Moduvent includes a dynamic module loader for plugin architecture:

from moduvent import discover_modules

# Load all modules from the 'modules' directory (default)
discover_modules()

# Or specify a custom directory
discover_modules("plugins")

This will try to load all modules in the specified directory and register their event handlers if possible.

Logging

By default, Moduvent uses loguru for logging and all logging messages are hidden. You can configure the logger object to enable logging.

# in your files
from loguru import logger

# This is strongly recommended to avoid duplicate logs
# For more info, see: https://loguru.readthedocs.io/en/stable/resources/troubleshooting.html#why-are-my-logs-duplicated-in-the-output
logger.remove()

# add your own handlers
logger.add(...)

When it comes to detailed configuration, please refer to the loguru documentation.

API Reference

TODO

Module Structure

Modules should be placed in a directory (default: modules) with a structure similar as the following:

modules/
    analytics/
        __init__.py
        events.py
        ...
    auth/
        __init__.py
        ...
    notifications/
        __init__.py
        ...

Configuration

Moduvent uses loguru for logging, which can be configured using the logger object.

from moduvent import logger

# Intercept standard logging
logger.add(
    "moduvent.log",
    rotation="10 MB",
    retention="10 days",
    level="DEBUG"
)

TODOs

  • Event priorities and consequences

  • Customized exception handling

  • Cached callbacks

  • Optimized data structures of _subscriptions

  • Handling duplicate subscriptions

  • Documentation of events

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

moduvent-5.0.tar.gz (21.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

moduvent-5.0-py3-none-any.whl (16.4 kB view details)

Uploaded Python 3

File details

Details for the file moduvent-5.0.tar.gz.

File metadata

  • Download URL: moduvent-5.0.tar.gz
  • Upload date:
  • Size: 21.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.12

File hashes

Hashes for moduvent-5.0.tar.gz
Algorithm Hash digest
SHA256 2ba2f667b0a614855a5600b224c47afe26db07196aec2636a82cd9f26528dfcb
MD5 7f09f7398512d5cb15516be630edf592
BLAKE2b-256 715e3f1576ffb1434989a7d28d6a7962b09ef8075c01b12d9376252b560e8748

See more details on using hashes here.

File details

Details for the file moduvent-5.0-py3-none-any.whl.

File metadata

  • Download URL: moduvent-5.0-py3-none-any.whl
  • Upload date:
  • Size: 16.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.12

File hashes

Hashes for moduvent-5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4a2bc0e2e5cd528239b9188f84dc31012afd1488c7c760f6f29ed0d68099b1ca
MD5 224f742fa8ce71a5ad3041c6957c4ad6
BLAKE2b-256 b459e3031a85804a9908aaac1344ccac65265582195c7d008bcde7a2707b596a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page