Both inputs now declare dora's Arrow struct {width, height, encoding, data}
rather than a flat buffer plus loose metadata. The payload describes itself, so
nothing about its shape has to be agreed out of band, and the frame travels as
one Arrow value instead of a buffer whose meaning lives in a sidecar dict.
Depth uses the same type. dora's registry has no depth type, and a depth map is
an image whose pixels are distances -- the reading ROS takes as well -- so it
arrives with a single-channel encoding: 32FC1/float32 or 16UC1/mono16/uint16.
`units` stays in message metadata because the struct has no field for it.
decode.IMAGE_TYPE is the single definition of the struct; the example source
and the tests build payloads from it rather than respelling the schema.
The older shapes are still decoded -- a flat UInt8 buffer with
width/height/encoding for image, a flat Float32 buffer with shape/units for
depth -- so a producer's payload can move before its manifest does. That is
only half a migration path: type compatibility is directional, so a producer
still declaring std/core/v1/UInt8 fails validate against an
std/media/v1/Image input regardless of what it sends, and has to update its
manifest too.
Verified: 41 tests, validate clean with 4 contracts injected, the dataflow runs
to a clean exit, and a composite rendered through the struct path is identical
to the one rendered before the migration.
57 lines
2.2 KiB
YAML
57 lines
2.2 KiB
YAML
# The repository's own example, and its end-to-end test: a synthetic source
|
|
# feeding the viewer. Everything it needs is in this checkout -- no camera, no
|
|
# detector, no network -- so it is also what CI runs.
|
|
#
|
|
# Both nodes are built from the checkout with `path:` + `build:`, which is what
|
|
# lets `dora validate` pick up the typed contract in dora-node.yml. A consumer
|
|
# wires the viewer from a tag instead -- see README.md.
|
|
#
|
|
# Run it with `--uv` so every node gets its own managed environment.
|
|
strict_types: true
|
|
|
|
nodes:
|
|
- id: source
|
|
# Run through the interpreter rather than as `path: examples/source.py`.
|
|
#
|
|
# A dora-node.yml describes exactly one node and is what gets published
|
|
# (`dora hub publish` expects it beside pyproject.toml), and this
|
|
# repository ships one node: dora-image-view. The example source is a test
|
|
# fixture, not a node anyone installs, so it gets no manifest.
|
|
#
|
|
# That has a mechanical consequence. `dora validate` matches a manifest to
|
|
# a `path:` node by entrypoint, so a path node here would be tried against
|
|
# the root manifest, would not match its `dora-image-view` entrypoint, and
|
|
# would warn -- which strict_types turns into a failure. Going through the
|
|
# interpreter leaves nothing for it to match, and `output_types` below is
|
|
# the documented way to type an output without one.
|
|
path: python
|
|
args: examples/source.py
|
|
# The source needs dora-rs, numpy and pyarrow; installing the project gives
|
|
# it exactly the versions pinned in uv.lock.
|
|
build: pip install .
|
|
inputs:
|
|
tick: dora/timer/millis/33
|
|
outputs:
|
|
- image
|
|
- depth
|
|
- camera_info
|
|
- bbox
|
|
- text
|
|
# bbox is deliberately absent: it is untyped on the viewer's side too,
|
|
# because senders disagree on 32- vs 64-bit numeric fields.
|
|
output_types:
|
|
image: std/media/v1/Image
|
|
text: std/core/v1/String
|
|
depth: std/media/v1/Image
|
|
camera_info: std/core/v1/Float32
|
|
|
|
- id: view
|
|
path: dora-image-view
|
|
build: pip install .
|
|
inputs:
|
|
image: source/image
|
|
depth: source/depth
|
|
camera_info: source/camera_info
|
|
bbox: source/bbox
|
|
text: source/text
|