PyDispatcher
PyDispatcher is a multi-producer, multi-consumer in-memory signal dispatch system for Python. It provides a robust mechanism for event routing, originally extracted from Django's dispatch module. Primarily maintained by Mike Fletcher, the library is currently at version 2.0.7 and sees infrequent but ongoing updates.
Warnings
- gotcha Receiver functions must accept `sender` as the first positional argument and `**kwargs` for any additional arguments. Failing to include `**kwargs` can cause runtime errors if the signal sender later provides arguments not explicitly defined in the receiver's signature.
- gotcha The `dispatcher.connect` method defaults to listening for signals from `dispatcher.Any` sender, while `dispatcher.send` defaults to sending signals with `dispatcher.Anonymous` sender. This difference can lead to signals not being received if not explicitly specified.
- gotcha While `dispatcher.send` accepts positional arguments, it is generally recommended to use keyword arguments for all data passed with a signal. Positional arguments can lead to conflicts with receiver signatures if not carefully managed.
- breaking Disconnecting a receiver within another receiver's execution flow might prevent subsequent receivers for the same signal from being called.
- gotcha There's an open issue where PyDispatcher's internal `robustApply` module may not fully support Python's keyword-only arguments, which could impact how signal arguments are processed if receivers rely heavily on them.
Install
-
pip install pydispatcher
Imports
- dispatcher
from pydispatch import dispatcher
Quickstart
from pydispatch import dispatcher
# Define a signal name (can be any hashable object)
MY_SIGNAL = 'my_custom_event'
def my_receiver(sender, **kwargs):
"""A function to receive the signal."""
print(f"Receiver got signal from {sender}: {kwargs}")
def another_receiver(sender, data, event_type, **kwargs):
"""Another receiver that expects specific keyword args."""
print(f"Another receiver got signal from {sender}: data={data}, type={event_type}")
class MySender:
def __init__(self, name):
self.name = name
def trigger_event(self):
print(f"\n{self.name} is sending MY_SIGNAL...")
# Send the signal, specifying the sender and any keyword arguments
dispatcher.send(signal=MY_SIGNAL, sender=self, data='important data', event_type='click')
# Connect receivers to the signal
# Use dispatcher.Any to receive signals from any sender
dispatcher.connect(receiver=my_receiver, signal=MY_SIGNAL, sender=dispatcher.Any)
dispatcher.connect(receiver=another_receiver, signal=MY_SIGNAL, sender=MySender)
# Create a sender instance and trigger the event
sender_instance = MySender(name="ComponentA")
sender_instance.trigger_event()
# Disconnect a receiver (optional)
dispatcher.disconnect(receiver=my_receiver, signal=MY_SIGNAL, sender=dispatcher.Any)