Skip to main content

Pythonic implementations of Command and Event Buses

Build Status Coverage Status

Zero-dependencies, flexible implementation of Command Bus. Python 3.6+ only

Basic usage of CommandBus

from typing import List

from pybuses import CommandBus


# Firstly, create command class
class MakeSandwich:
    def __init__(self, ingredients: List[str]) -> None:
        self.ingredients = ingredients


# Then create callable responsible for handling command.
# It must accept only one argument and is required to have type annotation for it.
def sandwich_maker(command: MakeSandwich) -> None:
    print(f'Making sandwich with {command.ingredients}!')


# finally, register the handler by subscribing
command_bus = CommandBus()
command_bus.subscribe(sandwich_maker)
command_bus.handle(MakeSandwich(['cheese', 'ham']))

Middlewares

Middlewares are lightweight plugins that let us inject custom logic before and after given command was handled.

Context managers are for now the only supported way of defining middlewares. They simplify exception handling and specifying whether middleware logic should be executed before or after handling event.

import contextlib
from typing import (
    Any,
    Generator,
)

@contextlib.contextmanager
def example_middleware(command: Any) -> Generator:
    print(f'Before handling {command}')
    yield
    print(f'After handling {command}')


command_bus = CommandBus([example_middleware])
command_bus.subscribe(sandwich_maker)
command_bus.handle(MakeSandwich(['cheese', 'ham']))

Basic usage of EventBus

from decimal import Decimal

from pybuses import EventBus


# Create event
class PaymentMade:
    amount: Decimal
    who: int

    def __init__(self, amount: Decimal, who: int) -> None:
        self.amount = amount
        self.who = who


def handler(payment_made: PaymentMade) -> None:
    print(f'Oh, cool! {payment_made.who} paid {payment_made.amount / 100}$!')


event_bus = EventBus()
event_bus.subscribe(handler)
event_bus.post(PaymentMade(Decimal('10.99'), 123))

Similarities & differences between Event- and CommandBus

EventBus can have 0 or many handlers subscribed to every event, while CommandBus must have exactly one handler for each command.

CommandBus supports middlewares while EventBus does not.

data classes compatible

Using dataclasses for building commands/events is supported

from dataclasses import dataclass
from typing import List

from pybuses import CommandBus


@dataclass
class MakeSandwich:
    ingredients: List[str]


def handler(command: MakeSandwich) -> None:
    print(f'dataclass-based command: {command}')


command_bus = CommandBus()
command_bus.subscribe(handler)
command_bus.handle(MakeSandwich(['ham', 'butter']))

attrs compatible

Using attrs for building commands/events is supported

import attr
from pybuses import CommandBus


@attr.s(frozen=True)
class Example:
    number: int = attr.ib()
    name: str = attr.ib()


def example_handler(command: Example) -> None:
    print(f'Inside handler of {type(command)} - got {command}!')


command_bus = CommandBus()
command_bus.subscribe(example_handler)
command_bus.handle(Example(number=1, name='Sebastian'))

Metadata

Release files for pybuses 1.1.0

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

Source distribution (sdist)

Source distribution for pybuses 1.1.0
File Size Uploaded Provenance Actions
pybuses-1.1.0.tar.gz 4.5 kB Without provenance Details for pybuses-1.1.0.tar.gz

Built distribution (wheel)

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

Total release size: 11.5 kB

Release files / pybuses-1.1.0.tar.gz

Download URL pybuses-1.1.0.tar.gz
Size 4.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ef69ba58be97d0747b47c29bdcb06621909fe00ae778b5da87fc995a09348e7a
BLAKE2b-256 checksum
How to use checksums
e19523f0e6b0c8f300eb8a6e26ea6b9921c5bcb78a2507cd08774788a220b1c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.12.1 pkginfo/1.4.2 requests/2.18.4 setuptools/40.6.3 requests-toolbelt/0.8.0 tqdm/4.29.0 CPython/3.6.4

Release files / pybuses-1.1.0-py3-none-any.whl

Download URL pybuses-1.1.0-py3-none-any.whl
Size 7.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3c28d261c69ece867fbb4af3cdb6a7ffb76425b6c8c0f2dc4aa7fdec78147dfd
BLAKE2b-256 checksum
How to use checksums
984b5dc1e0b60d2806c7fcdf108f852a09dcef03316d100c295a8087d7665b2f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.12.1 pkginfo/1.4.2 requests/2.18.4 setuptools/40.6.3 requests-toolbelt/0.8.0 tqdm/4.29.0 CPython/3.6.4

Security for pybuses 1.1.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files No provenance

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