Libby: a tiny messaging library which uses Bamboo with pluggable transports (ZMQ or RabbitMQ)
To install the package in editable mode (ideal for development), follow these steps:
- Python 3.7 or higher
pip(ensure it's the latest version)setuptools42 or higher (for building the package)
First, clone the repository to your local machine:
git https://github.com/CaltechOpticalObservatories/libby
cd libbyCreate a virtual environment for your package:
python -m venv venv
source venv/bin/activateMake sure setuptools and pip are up to date:
pip install --upgrade pip setuptools wheelTo install your package in editable mode for development, use the following command:
pip install -e .This will install the package, allowing you to edit it directly and have changes take effect immediately without reinstalling.
To install any optional dependencies, such as development dependencies, use:
pip install -e .[dev]A keyword is a typed named value served over libby, with a uniform payload convention:
{}→ show (return current value){"value": V}→ modify (apply, then return it)
Types: BoolKeyword, IntKeyword, FloatKeyword, StringKeyword,
TriggerKeyword. Access mode is inferred — pass a getter for
read-only, a setter for write-only, both for read-write. Optional
extras: units, description, nullable, validator.
Each Libby peer carries a keyword_registry with typed builder
methods. Build keywords by calling lib.keyword_registry.<type>(...),
then flush them to the peer with register_keywords:
from libby import Libby
libby = Libby.rabbitmq(self_id="my-peer", rabbitmq_url="amqp://localhost")
state = {"position": 0.0}
libby.keyword_registry.bool("online", getter=lambda: True)
libby.keyword_registry.float("position",
getter=lambda: state["position"],
setter=lambda v: state.update(position=v),
units="mm")
libby.keyword_registry.trigger("halt", action=lambda: print("halted"))
libby.register_keywords(libby.keyword_registry.drain())You can also build keywords directly via BoolKeyword(...) /
FloatKeyword(...) etc. and pass a list to register_keywords. The
registry is a convenience layer over the same type classes.
Clients call the keyword by name:
client = Libby.rabbitmq(self_id="client", rabbitmq_url="amqp://localhost")
client.rpc("my-peer", "position", {}) # show
client.rpc("my-peer", "position", {"value": 12.5}) # modify
client.rpc("my-peer", "halt", {"value": 1}) # fireTwo meta-services are auto-registered on every peer that uses the keyword registry:
keys.list— payload{"pattern": "..."}(default"%") → names, sorted.%wildcards within a single name.keys.describe— payload{"name": "..."}→ flat metadata dict. Exact lookup; no wildcards.