Skip to main content

Dora Utils

This repository contains some simple utilities for using dora that improve QoL.

To install, run

pip install dora-utils

For simple usage examples, see dora_utils.examples.

The DoraNode class

The usual workflow in dora is to define a Node, which acts as an iterator over events. In this loop, you can then manually handle the events as they arrive in the node. We provide a convenient DoraNode convenience class to register callbacks on events in a more ROS-style fashion. Consider the talker.py and listener.py examples:

# talker.py
import pyarrow as pa

from dora_utils.node import DoraNode, on_event


class Talker(DoraNode):
    """Simple publisher node for a Dora tutorial."""

    @on_event("INPUT", "tick")
    def talk(self, event: dict) -> None:
        self.node.send_output("speech", pa.array(["Hello World"]))
# listener.py
from dora_utils.node import DoraNode, on_event


class Listener(DoraNode):
    """Simple publisher node for a Dora tutorial."""

    def __init__(
        self, node_id: str = "listener", max_workers: int | None = None, override_msg: str | None = None
    ) -> None:
        """Initialize the listener."""
        super().__init__(node_id=node_id, max_workers=max_workers)
        self.override_msg = override_msg

    @on_event("INPUT", "speech")
    def listen(self, event: dict) -> None:
        if self.override_msg is not None:
            message = self.override_msg
        else:
            message = event["value"][0].as_py()
        print(f"""I heard {message} from {event["id"]}""")

The on_event decorator provides a simple interface for registering callbacks to inputs specified into the node using dora's dataflow.yml. You can register the same callback to multiple inputs by instead passing a sequence of input names into on_event.

Hydra Configuration

One sharp edge regarding dora is node configuration. The typical workflow is writing a script-style program where you can manually configure nodes and spin them. This is a bit cumbersome once the system scales up to many nodes with many arguments that you might want to configure in a more organized way. We provide an example design pattern that combines the dataflow.yml configuration system from dora with hydra.

For an example, consider scripts/chatter.yaml, which both defines a simple "chatter" workflow between a talker and listener node.

# this section of the configuration specifies the dora dataflow
dataflow:
  nodes:
    - id: talker
      path: dynamic
      inputs:
        tick: dora/timer/millis/10
      outputs:
        - speech
    - id: listener
      path: dynamic
      inputs:
        speech: talker/speech

# everything else is used to instantiate and spin the nodes with hydra
node_definitions:
  talker:  # <--- this name doesn't matter
    _target_: dora_utils.examples.chatter.talker.Talker
    node_id: talker
    max_workers: null
  listener:  # <--- this name doesn't matter
    _target_: dora_utils.examples.chatter.listener.Listener
    node_id: listener
    max_workers: null
    override_msg: null

Everything under the dataflow section is the "standard" dora dataflow, which defines the nodes, their IDs, their inputs/outputs, etc. Under node_definitions is a list of hydra targets, so you can instantiate arbitrarily complicated nodes using hydra's composition API. Above, you'll see that there are comments saying "this name doesn't matter." We use this yaml syntax because we want to be able to use hydra's configuration override syntax to preserve default values. Because lists are atomic in hydra, we can't override single list elements, so in any file that specifies another configuration file as a default, we would have to copy and paste the entire node_definitions section. When we instead structure things like a dictionary, overrides work!

If we run

python scripts/run.py -cn chatter

we will start the chatter example, and we should see the following printed a lot:

I heard Hello World from speech
I heard Hello World from speech
I heard Hello World from speech

Now, if we modify chatter.yaml to instead show

node_definitions:
  talker:
    _target_: dora_utils.examples.chatter.talker.Talker
    node_id: talker
    max_workers: null
  listener:
    _target_: dora_utils.examples.chatter.listener.Listener
    node_id: listener
    max_workers: null
    override_msg: "override"  # change this field for this example!

and run the same command, we will see

I heard override from speech
I heard override from speech
I heard override from speech

When you import the dora_utils package to your own project, you can use the hydra configuration design pattern as in our scripts/run.py file:

from pathlib import Path

import hydra
from omegaconf import DictConfig

from dora_utils.launch.run import run

CONFIG_PATH = Path(__file__).parent / "configs"


@hydra.main(config_path=str(CONFIG_PATH), config_name="default", version_base="1.3")
def main(cfg: DictConfig) -> None:
    """Main function to run a dora stack via a hydra configuration yaml file."""
    run(cfg)


if __name__ == "__main__":
    main()

The main variables to change in your downstream project are the configuration path and configuration name. Note that these can easily be overwritten from the command line, e.g., as follows:

python scripts/run.py -cp <my_config_path> -cn <my_config_name>

Metadata

Release files for dora-utils 0.1.1

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

Source distribution (sdist)

Source distribution for dora-utils 0.1.1
File Size Uploaded
dora_utils-0.1.1.tar.gz 11.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dora-utils 0.1.1
File Interpreter ABI Platform
dora_utils-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 21.1 kB

Release files / dora_utils-0.1.1.tar.gz

Download URL dora_utils-0.1.1.tar.gz
Size 11.0 kB
Tags Source
SHA-256 checksum
How to use checksums
bd3df50b6e871903e867a312e0c59e96733184ebc438c2343bfd854419bd69ca
BLAKE2b-256 checksum
How to use checksums
5900d0ff029be346adc16981faa69cbe931649cdb635fe467628e1a4de64ecd2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Release files / dora_utils-0.1.1-py3-none-any.whl

Download URL dora_utils-0.1.1-py3-none-any.whl
Size 10.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
263172a8d7595615ffe7cf26b3c8502c6944a70db17a98190b9697caeddef7d2
BLAKE2b-256 checksum
How to use checksums
78620ffc083b1d5f7c95eb03b260d2622dfacb70d1153011d216260b71c8e7d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

0.0.1

1 release file

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