Metadata-Version: 2.5
Name: dispio
Version: 0.0.2
Summary: A transport-independent, declarative dispatch engine designed for pyev broker routing and general Python dispatch.
Author-email: leydotpy <leydotpy.dev@gmail.com>
License: MIT
License-File: LICENSE
Keywords: asyncio,broker,dispatch,event,plugins,python,router
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.12
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.2; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# dispio

`dispio` is a general-purpose declarative dispatch engine designed to work in two roles:

1. underneath a `broka`/broker Router for local handler resolution; and
2. independently in ordinary Python modules for key, type, wildcard, namespace, header, predicate, and plugin dispatch.

It deliberately does **not** own broker acknowledgements, retries, dead-letter policy, connection lifecycle, serialization, or transport I/O. Those remain responsibilities of the broker framework.

## Installation

```bash
pip install dispio
```

## Exact-key dispatch

```python
from dispio import Dispatcher

dispatcher = Dispatcher(name="commands")


@dispatcher.register("user.create")
def create_user(command):
    return command["email"]


result = dispatcher.dispatch(
    {"email": "alice@example.com"},
    __dispatch_key="user.create",
)
```

## Type dispatch

```python
from dataclasses import dataclass
from dispio import Dispatcher


@dataclass
class StartMeeting:
    room_id: int


commands = Dispatcher(name="command-bus")


@commands.register_type(StartMeeting)
async def start(command: StartMeeting):
    return command.room_id


result = await commands.dispatch_async(StartMeeting(42))
```

## Wildcard routing / fanout

```python
router = Dispatcher(name="events")

@router.pattern("videoroom.*")
async def audit(event):
    ...

@router.register("videoroom.publisher.joined", priority=10)
async def joined(event):
    ...

# Resolve/execute every matching handler.
await router.dispatch_all_async(event, __dispatch_key="videoroom.publisher.joined")
```

## Predicate dispatch

```python
@dispatcher.when(lambda payment, ctx: payment.amount >= 1_000_000, priority=100)
def high_value(payment):
    return "review"
```

## broka bridge

```python
from dispio import Dispatcher
from dispio.integrations import BrokaDispatchBridge

core = Dispatcher(name="broka-router")
router = BrokaDispatchBridge(core)


@router.on("videoroom.*")
async def handle(delivery):
    ...


# Called by broka's inbound pipeline after envelope decoding/middleware:
await router.dispatch_delivery_all(delivery)
```

The bridge passes the framework `Delivery` object to handlers, so broka retains acknowledgement, retry, DLQ, observability, and delivery-state semantics.

See `docs/architecture.md` and `INTEGRATION.md` for the intended integration boundary.
