Skip to main content

Rembus for Python

Docs Stable Docs Dev Build Status Coverage

Rembus is a Pub/Sub and RPC middleware.

Features

  • Binary message encoding using CBOR.

  • Native support for exchanging DataFrames.

  • Persistent storage via DuckDB DuckLake.

  • Pub/Sub QOS0, QOS1 and QOS2.

  • Hierarchical topic routing with wildcards (*/*/temperature).

  • MQTT integration.

  • WebSocket transport.

See Rembus.jl broker for a full fledged broker that supports WebSocket, ZMQ and plain tcp protocols and more features like private topics, multi-tenancy and more.

Concepts

  • Component: an addressable node in a distributed system. A component connects to a broker and communicates using Pub/Sub and/or RPC semantics.

  • Broker: a specialized component responsible for routing Pub/Sub messages and dispatching RPC calls between components. A broker may also persist messages and expose services.

  • Topic: a "logical channel" string identifier used for Pub/Sub message routing (e.g. alarm_topic).

  • Topic space: a set of topics defined by wildcard patterns (e.g. */telemetry) used for bulk subscription..

  • Subscription: a callback bound to a topic or topic space; invoked automatically with the message payload when a Pub/Sub message is published. Supports wildcard topics and optional delivery of messages sent while the subscriber was offline (msgfrom=rb.LastReceived).

  • RPC Service: a named function exposed by a component and registered at the broker for remote invocation.

  • RPC Call: a synchronous or asynchronous request issued by a component to invoke a remote RPC service.

  • Schema: an optional declarative mapping between topic patterns and persistent storage tables, used to structure and persist messages at rest.

  • Data at Rest: broker capability to persist published messages into DuckDB tables defined by a schema, enabling historical queries and analytics.

Getting Started

Install the package:

pip install rembus

Broker

Start a broker (sync or async):

import rembus as rb

# sync version
bro = rb.node() # equivalent to rb.node(port = 8338)
bro.wait() # event loop, not needed in interactive interpreter


# async version
bro = await rb.component()
await bro.wait() 

Broker with persistent storage

A Rembus broker can be configured with a schema to persist published messages into a DuckDB database via the DataLake extension.

A schema declaratively maps Pub/Sub topic patterns to relational tables. Topics variables are extracted from the topic path and mapped to table columns; message payload fields are mapped to the remaining columns.

Example schema.json:

{
    "tables": [
        {
            "table": "sensor",
            "topic": ":site/:type/:dn/sensor",
            "columns": [
                {"col": "site", "type": "TEXT", "nullable": false},
                {"col": "type", "type": "TEXT", "nullable": false},
                {"col": "dn", "type": "TEXT"}
            ],
            "keys": ["dn"]
        },
        {
            "table": "telemetry",
            "topic": ":dn/telemetry",
            "columns": [
                {"col": "dn", "type": "TEXT"},
                {"col": "temperature", "type": "DOUBLE"},
                {"col": "pressure", "type": "DOUBLE"}
            ],
            "extras": {
                "recv_ts": "ts",
                "slot": "time_bucket"
            }
        }
    ]
}

Schema semantics

  • Each entry in tables defines a topic-to-table binding.

  • Topic segments prefixed with : are variables extracted from the topic path and written to the corresponding columns.

  • Message payload fields are mapped positionally or by name to remaining columns.

  • keys define logical primary keys.

  • extras specify broker-generated metadata (e.g. receive timestamp, time bucketing).

Example mappings

  • Messages published to :site/:type/:dn/sensor are persisted in the sensor table, with site, type, and dn derived from the topic path.

  • Messages published to :dn/telemetry are persisted in the telemetry table, with metric values extracted from the message payload.

If a schema is provided, DuckLake tables are created automatically if they do not already exist, and all matching publications are persisted.

For each table three special topics for RPC services are automatically created:

  • upsert_<table> insert/update records;
  • query_<table> retrieve records;
  • delete_<table> remove records;

RPC calls to query_* topics return a Polars DataFrame.

For example:

cli.rpc("query_sensor", {"where": "type='HVAC'"})

Starting a broker with storage enabled

import rembus as rb

bro = await rb.component(schema="schema.json")
await bro.wait() 

Components

Connect to a Broker:

# named component
cli = await rb.component("ws://host:8338/myname")

# default host/port
cli = await rb.component("myname")

# anonymous
cli = await rb.component(rb.anonym(host="host", port=8338))

Why named components

  • Enables authentication (RSA/ECDSA/shared secret).

  • Allows persistent twin mapping; offline messages are buffered. A Component connects to a Broker using a URL-like formatted string that identifies the broker address and declare the name of the Component.

Pub/Sub

Publish

# Single message
await cli.publish("site/type/dn/sensor")
await cli.publish("dn/telemetry", {'temperature': 21.6, 'pressure': 980})

# DataFrame
import polars as pl
df = pl.DataFrame({"dn":["s1","s2"], "temperature":[15,18.8]})
await cli.publish("telemetry", df)

Subscribe

# Single topic
def alarm(slogan, severity):
    print(f"{slogan}: {severity}")

sub = rb.node("monitor")
sub.subscribe(alarm, topic="alarm") # equivalent to sub.subscribe(alarm)

# Topic space
def telemetry(topic, data):
    print(f"{topic}: {data}")

sub.subscribe(telemetry, topic="**/telemetry", msgfrom=rb.LastReceived)

The subscribed alarm function gets called with the using the message payload: slogan as first argument and severity as second argument:

cli.publish("alarm", "mydevice: battery very low", "CRITICAL")

The option msgfrom is for receiving published messages when the component was not subscribed to the topic, for example because it was not connected when the messages was published.

RPC

Expose

import rembus as rb

def add(x,y):
    return x+y

handle = rb.node('calculator')
handle.expose(add)
handle.wait()

Call

import rembus as rb

handle = rb.node("myclient")
result = handle.rpc('add', 1, 2)

Metadata

Release files for rembus 0.8.16

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

Source distribution (sdist)

Source distribution for rembus 0.8.16
File Size Uploaded
rembus-0.8.16.tar.gz 63.4 kB Details

Built distribution (wheel)

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

Total release size: 129.0 kB

Release files / rembus-0.8.16.tar.gz

Download URL rembus-0.8.16.tar.gz
Size 63.4 kB
Tags Source
SHA-256 checksum
How to use checksums
e1c3bae66154e09e3f16e43c4c726d9f14566f785308dfed1a32bc085abe7371
BLAKE2b-256 checksum
How to use checksums
69cf09c5b97d8e211d5bde24c5a5ccae9fbe1853732f927c96f8f98d60b022d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.

Transparency log

Release files / rembus-0.8.16-py3-none-any.whl

Download URL rembus-0.8.16-py3-none-any.whl
Size 65.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e0f52ad93509674f746fad50a36574f3d43b4376e5498f82b70460ae1c902391
BLAKE2b-256 checksum
How to use checksums
98abe8a9479f36617b0a2007a1053c0a62106474e106215541fec17a9889b4aa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.8.23

2 release files

0.8.19

2 release files

0.8.18

2 release files

0.8.17

2 release files

This release

0.8.16 This release

2 release files

0.8.15

2 release files

0.8.14

2 release files

0.8.13

2 release files

0.8.10

2 release files

0.8.9

2 release files

0.8.8

2 release files

0.8.7

2 release files

0.8.6

2 release files

0.8.5

2 release files

0.8.4

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.5

2 release files

0.1.0

2 release files

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