Skip to main content

No project description provided

Project description

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>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dora_utils-0.1.0.tar.gz (10.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dora_utils-0.1.0-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file dora_utils-0.1.0.tar.gz.

File metadata

  • Download URL: dora_utils-0.1.0.tar.gz
  • Upload date:
  • Size: 10.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for dora_utils-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c4688a3d96fad658ce711747697e77cbaea225398c0eef98af3a4199d5624217
MD5 16dfc747b9a0bf58338f2ae61a4ba8c4
BLAKE2b-256 c72c195e171d1f120ce35657a735b5189ba4ce5f91bc597255ecce669b6c24d4

See more details on using hashes here.

File details

Details for the file dora_utils-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dora_utils-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for dora_utils-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 98f38c210c9a2443010d562ed2c83a94d5bca3dc286c7cdf278f4edd2fe0c24c
MD5 506e0a45ed43a77c352c662314f60ddf
BLAKE2b-256 72eebbde16bd70ebcaee73288f04290bcab8eb89c0f66ebe59107a5021aa7792

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page