Skip to main content

babbelfish

A lightweight async service framework used by every sensor service in this workspace. Provides two base classes plus convention-driven YAML loading on top of heisskleber transports.

The goal is to let a service implementation be a single file: one @dataclass for configuration, one subclass of Service with an async runner(), and nothing else. Everything else — signal handling, sender wiring, config-file parsing — is handled here.


Quick tour

from dataclasses import dataclass

from babbelfish import Service, ServiceConf


@dataclass
class MyServiceConf(ServiceConf):
    topic: str = "my-topic"
    poll_interval: float = 1.0


class MyService(Service):
    def __init__(self, config: MyServiceConf) -> None:
        self.config = config
        self.senders = list(config.senders.values())
        super().__init__(config)

    async def runner(self) -> None:
        while True:
            payload = {"epoch": ..., "value": 42}
            await asyncio.gather(
                *[s.send(payload, topic=self.config.topic) for s in self.senders]
            )
            await asyncio.sleep(self.config.poll_interval)


if __name__ == "__main__":
    config = MyServiceConf.from_file("config.yaml")
    service = MyService(config)
    service.start()
    asyncio.run(service.task)

Example config.yaml:

name: "my-service"
topic: "/my-topic"
poll_interval: 0.5

output:
  mqtt:
    host: localhost
    port: 1883
  zmq:
    host: 127.0.0.1
    port: 5555
  file:
    rollover: 3600
    name_fmt: "mine_%Y%m%dT%H%M%S.csv"
    directory: "/tmp"
    format: "csv"

ServiceConf

Dataclass base for service configuration. Subclass it, add your own fields, and call from_file(path) to load a YAML config.

Built-in fields

Field Type Default Meaning
name str — Service name. Also used as the logging.getLogger key.
precision int 6 Rounding precision for float payload fields (services apply this at publish time).
senders dict[str, Sender[Any]] {} Populated automatically from the output: section of the YAML.
receivers dict[str, Receiver[Any]] {} Populated automatically from the input: section of the YAML.

Class methods

  • from_file(path) — load a YAML file and delegate to from_dict.
  • from_dict(data) — pop output: / input: sections, instantiate the matching heisskleber transports via their registry, drop unknown top-level keys, and return an instance of the subclass.

output: / input: sections

The first word of each key (before the first _) selects which heisskleber transport is used. Multiple instances of the same protocol are supported by suffixing:

output:
  mqtt:          # first MQTT sender
    host: primary
  mqtt_backup:   # second MQTT sender
    host: secondary
  zmq:
    host: 127.0.0.1
    port: 5555

The sub-dict under each key is passed to the corresponding heisskleber config class (MqttConf, ZmqConf, FileConf, …). Unknown protocols raise ValueError at load time.

After loading, config.senders is a dict[str, Sender] keyed by the original label ("mqtt", "mqtt_backup", "zmq", …). Services typically access them as a plain list: list(config.senders.values()).

Subclassing for nested structures

ServiceConf.from_dict silently drops unknown keys. If your config has nested structure (lists of dicts, typed sub-objects, …), override from_dict in your subclass — see msb_can.service.CanConf for an example that parses a channels: list into typed ChannelConf instances.


Service

Abstract base class for async services. Handles signal registration, logger setup, and task lifecycle.

Required override

@abstractmethod
async def runner(self) -> None:
    ...

runner is expected to be an infinite loop that produces and publishes data. It runs as an asyncio.Task created by start().

Override hooks (all optional)

Hook Called when Default
start_hook() Before runner() starts Logs Starting <name> service
stop_hook() On shutdown (SIGINT / SIGTERM) Logs Stopping <name> service
exit_hook() On SIGINT Logs Exiting <name> service
exception_hook() On unhandled exception in runner() Logs the exception

stop_hook() is where hardware teardown belongs — close serial ports, disconnect I²C, stop driver threads, etc.

Signal handling

Service.__init__ installs handlers for SIGINT and SIGTERM that:

  1. Cancel every other task on the event loop.
  2. Gather them to surface any exceptions.
  3. Log Program crashed successfully. and stop the loop.

Derived services must not install their own signal handlers — the base class owns the loop-level handlers.

Logger

self.logger is logging.getLogger(config.name). Pair this with a logging.yaml that configures a logger whose key matches config.name:

loggers:
  my-service:          # matches config.name
    level: INFO
    handlers: [console]
    propagate: no

Installation

Within the workspace:

[tool.uv.sources]
babbelfish = { workspace = true }

[project]
dependencies = [
    "babbelfish>=0.1.3",
    # …
]

Outside the workspace, install from PyPI:

uv pip install babbelfish

Or pin to a specific version:

uv pip install "babbelfish>=0.1.4"

Dependencies

  • heisskleber — provides the Sender / Receiver transport abstractions and their registries. All services in this workspace publish via heisskleber only; paho-mqtt / pyzmq are never imported directly from a service.

Running the tests

uv run --no-sync pytest packages/babbelfish/tests/

Metadata

Release files for babbelfish 0.1.4

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

Source distribution (sdist)

Source distribution for babbelfish 0.1.4
File Size Uploaded Provenance
babbelfish-0.1.4.tar.gz 6.1 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 13.2 kB

Release files / babbelfish-0.1.4.tar.gz

Download URL babbelfish-0.1.4.tar.gz
Size 6.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c4f0784e24320035e8a837dd593814ca13847c3280e6d72f828b922cee0191cf
BLAKE2b-256 checksum
How to use checksums
969dab42c1b064a3f6ee46e0b4209c49281c1a0bf10e64e2705305a9481fadfd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / babbelfish-0.1.4-py3-none-any.whl

Download URL babbelfish-0.1.4-py3-none-any.whl
Size 7.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
88a8ea968e323e8dbc71a47fa9aeb9c2335851fd80872e9d72357b97c42df428
BLAKE2b-256 checksum
How to use checksums
2b7698d409bf81e894873358949f03d1503c9ff874d102edbc9e811125e35f78
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for babbelfish 0.1.4

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.

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