Skip to main content

A lightweight pub-sub framework.

Project description

splurge-pub-sub

PyPI version Python versions License: MIT

CI Coverage Ruff mypy

A lightweight, thread-safe publish-subscribe framework for Python applications. Splurge provides simple, Pythonic in-process event communication with full type safety and comprehensive error handling.

Features

  • Lightweight: Zero external dependencies, minimal footprint
  • Thread-Safe: Full concurrency support with reentrant locks
  • Type-Safe: Complete type annotations with mypy strict mode compliance
  • Async Publishing: Non-blocking message dispatch via background worker thread
  • Simple API: Subscribe, publish, unsubscribe with intuitive methods
  • Decorator Syntax: @bus.on("topic") for simplified subscriptions
  • Topic Filtering: Wildcard pattern matching for selective message delivery
  • Correlation IDs: Cross-library event tracking and coordination
  • Error Handling: Custom error handlers for failed callbacks
  • PubSubAggregator: Aggregate messages from multiple PubSub instances
  • Context Manager: Automatic resource cleanup with with statement
  • 95% Coverage: Comprehensive test coverage across all features

Quick Start

Installation

pip install splurge-pub-sub

Basic Usage

from splurge_pub_sub import PubSub, Message

# Create a pub-sub bus
bus = PubSub()

# Subscribe to a topic
def handle_event(msg: Message) -> None:
    print(f"Received: {msg.data}")

sub_id = bus.subscribe("user.created", handle_event)

# Publish a message (non-blocking, returns immediately)
bus.publish("user.created", {"id": 123, "name": "Alice"})
bus.drain()  # Wait for message to be delivered (optional)
# Output: Received: {'id': 123, 'name': 'Alice'}

# Unsubscribe when done
bus.unsubscribe("user.created", sub_id)

Decorator API

@bus.on("user.updated")
def handle_user_updated(msg: Message) -> None:
    print(f"User updated: {msg.data}")

bus.publish("user.updated", {"id": 123, "status": "active"})
bus.drain()  # Wait for delivery if needed

Topic Filtering

from splurge_pub_sub import TopicPattern

# Create patterns with wildcards
pattern = TopicPattern("user.*")
pattern.matches("user.created")  # True
pattern.matches("user.updated")  # True
pattern.matches("order.created")  # False

# Patterns with ? for single character
pattern = TopicPattern("user.?.created")
pattern.matches("user.a.created")  # True
pattern.matches("user.ab.created")  # False

Correlation ID for Cross-Library Coordination

# Multiple libraries using same correlation_id
correlation_id = "workflow-123"

dsv_bus = PubSub(correlation_id=correlation_id)
tabular_bus = PubSub(correlation_id=correlation_id)

# Monitor all events with same correlation_id
monitor_bus = PubSub()
monitor_bus.subscribe("*", lambda m: print(f"[{m.correlation_id}] {m.topic}"), 
                      correlation_id=correlation_id)

dsv_bus.publish("dsv.file.loaded", {"file": "data.csv"})
tabular_bus.publish("tabular.table.created", {"rows": 100})
monitor_bus.drain()  # Wait for messages to be delivered
# Both messages received by monitor

Error Handling

def my_error_handler(exc: Exception, topic: str) -> None:
    print(f"Error on topic '{topic}': {exc}")

bus = PubSub(error_handler=my_error_handler)

@bus.on("risky.operation")
def handle_event(msg: Message) -> None:
    raise ValueError("Something went wrong!")

bus.publish("risky.operation", {})
bus.drain()  # Wait for message delivery
# Output: Error on topic 'risky.operation': Something went wrong!

PubSubAggregator - Aggregating Multiple PubSub Instances

from splurge_pub_sub import PubSubAggregator, PubSub, Message

# Create PubSub instances from different packages/modules
pack_b_bus = PubSub()
pack_c_bus = PubSub()

# Create composite to aggregate messages from both
aggregator = PubSubAggregator(pubsubs=[pack_b_bus, pack_c_bus])

# Subscribe once to receive events from any managed PubSub
def unified_handler(msg: Message) -> None:
    print(f"Received from {msg.topic}: {msg.data}")

aggregator.subscribe("user.created", unified_handler, correlation_id="*")

# Publish from different PubSub instances
pack_b_bus.publish("user.created", {"id": 1, "source": "pack-b"})
pack_c_bus.publish("user.created", {"id": 2, "source": "pack-c"})

# Drain all buses to ensure messages are forwarded
pack_b_bus.drain()
pack_c_bus.drain()
aggregator.drain()

# Messages from both PubSub instances are received by composite subscribers

Context Manager

with PubSub() as bus:
    bus.subscribe("topic", callback)
    bus.publish("topic", data)
    bus.drain()  # Wait for delivery if needed
    # Cleanup happens automatically

Documentation

Requirements

  • Python 3.10 or later
  • No external dependencies

License

MIT License - see LICENSE file for details

Author

Jim Schilling

Support

For issues, questions, or contributions, visit the GitHub repository.

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

splurge_pub_sub-2025.3.1.tar.gz (30.8 kB view details)

Uploaded Source

Built Distribution

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

splurge_pub_sub-2025.3.1-py3-none-any.whl (37.2 kB view details)

Uploaded Python 3

File details

Details for the file splurge_pub_sub-2025.3.1.tar.gz.

File metadata

  • Download URL: splurge_pub_sub-2025.3.1.tar.gz
  • Upload date:
  • Size: 30.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for splurge_pub_sub-2025.3.1.tar.gz
Algorithm Hash digest
SHA256 cf8bc59adf8391f1242a2b9b6dab62596f14288d57243a36c212cdf50ac70c93
MD5 84cdfdf711fe0ea7c15cd0b8cbc89f96
BLAKE2b-256 5bb77801311ed7695b6287ce41f752d2f0864c8fbc5027aee3f0944f5d2baf34

See more details on using hashes here.

File details

Details for the file splurge_pub_sub-2025.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for splurge_pub_sub-2025.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 08f0e726aa891cefe1a3119b0db2c8f42487f83c367bdef48175c69bc80d9d4f
MD5 4971f74802350a1ed89f2904e4a0bc65
BLAKE2b-256 6b321550bf21fc3c22b73aaa482e57739cdf981b75eeb5542027accf505dfb47

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