From e2debe0581835ea96996b8d0f12af5d14815d450 Mon Sep 17 00:00:00 2001 From: fondef Date: Mon, 14 Sep 2026 16:08:48 -0500 Subject: [PATCH] refactor: rename the node from opencv-plot to dora-plot The repository is dora-plot, but the package, the entrypoint, the manifest name and the window title were all opencv-plot. Consumers wire the node by `path:`, so the split name was visible in every dataflow. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018WLVZCFFcCH1EpTXGfS9aD --- AGENTS.md | 8 +-- README.md | 6 +- dataflow.yml | 2 +- dora-node.yml | 6 +- {opencv_plot => dora_plot}/__init__.py | 0 {opencv_plot => dora_plot}/bbox.py | 2 +- {opencv_plot => dora_plot}/decode.py | 0 {opencv_plot => dora_plot}/main.py | 6 +- {opencv_plot => dora_plot}/plot.py | 2 +- pyproject.toml | 6 +- ...{test_opencv_plot.py => test_dora_plot.py} | 4 +- uv.lock | 72 +++++++++---------- 12 files changed, 57 insertions(+), 57 deletions(-) rename {opencv_plot => dora_plot}/__init__.py (100%) rename {opencv_plot => dora_plot}/bbox.py (97%) rename {opencv_plot => dora_plot}/decode.py (100%) rename {opencv_plot => dora_plot}/main.py (95%) rename {opencv_plot => dora_plot}/plot.py (98%) rename tests/{test_opencv_plot.py => test_dora_plot.py} (97%) diff --git a/AGENTS.md b/AGENTS.md index 9bfd6fa..5540eb3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,10 +36,10 @@ uv run ruff check . ## Architecture -- **`opencv_plot/main.py`** — Argument parsing and the dora event loop, nothing else. `image` decodes and redraws; `bbox` and `text` only store state. The env var wins over the CLI flag for `PLOT_WIDTH`/`PLOT_HEIGHT`, matching the upstream node. `Node(args.name)` rather than `Node()` so the node also runs standalone as a dynamic node. -- **`opencv_plot/decode.py`** — `to_bgr()`: every supported encoding to a writable BGR array. `width`/`height` are only consulted for the raw encodings (`bgr8`, `rgb8`, `yuv420`); the rest carry their own dimensions, so a missing dimension is an error only where it actually matters. Two behaviours are deliberate, not bugs: `bgr8` **copies** (the payload may be a read-only view on shared memory, and the frame is annotated in place), and `yuv420` converts with `COLOR_YUV420p2RGB` rather than `...2BGR` — the upstream node converts to RGB and then displays it as BGR, and that channel swap is part of the behaviour callers already see. -- **`opencv_plot/plot.py`** — `Plot` (the overlay state and the window) and `Bboxes`. `show()` draws, resizes and displays, and returns whether `q` was pressed. Resizing only happens when *both* `PLOT_WIDTH` and `PLOT_HEIGHT` are set. `headless` (from `CI=true`) skips only the window: every input is still decoded, which is what makes the node safe in a pipeline test. -- **`opencv_plot/bbox.py`** — Parses the `bbox` struct into xyxy corners. `xywh` is centre-based (x, y are the box centre). `_flat()` unwraps the single-element list that `pa.array([{...}])` produces around each field, and reads a field stored flat as-is. +- **`dora_plot/main.py`** — Argument parsing and the dora event loop, nothing else. `image` decodes and redraws; `bbox` and `text` only store state. The env var wins over the CLI flag for `PLOT_WIDTH`/`PLOT_HEIGHT`, matching the upstream node. `Node(args.name)` rather than `Node()` so the node also runs standalone as a dynamic node. +- **`dora_plot/decode.py`** — `to_bgr()`: every supported encoding to a writable BGR array. `width`/`height` are only consulted for the raw encodings (`bgr8`, `rgb8`, `yuv420`); the rest carry their own dimensions, so a missing dimension is an error only where it actually matters. Two behaviours are deliberate, not bugs: `bgr8` **copies** (the payload may be a read-only view on shared memory, and the frame is annotated in place), and `yuv420` converts with `COLOR_YUV420p2RGB` rather than `...2BGR` — the upstream node converts to RGB and then displays it as BGR, and that channel swap is part of the behaviour callers already see. +- **`dora_plot/plot.py`** — `Plot` (the overlay state and the window) and `Bboxes`. `show()` draws, resizes and displays, and returns whether `q` was pressed. Resizing only happens when *both* `PLOT_WIDTH` and `PLOT_HEIGHT` are set. `headless` (from `CI=true`) skips only the window: every input is still decoded, which is what makes the node safe in a pipeline test. +- **`dora_plot/bbox.py`** — Parses the `bbox` struct into xyxy corners. `xywh` is centre-based (x, y are the box centre). `_flat()` unwraps the single-element list that `pa.array([{...}])` produces around each field, and reads a field stored flat as-is. - **`dora-node.yml`** — Node manifest (`apiVersion: 1`). `dora validate` injects these types into any dataflow that reaches the node by `path:`; a `git:`-sourced node does **not** pick it up, which is why the dataflow builds from the checkout. `image` and `text` carry type URNs naming the element type (`std/core/v1/UInt8`, `.../String`) because each payload is a raw buffer described by its metadata, not an Arrow struct. `bbox` is deliberately **untyped**: senders disagree on whether its numeric fields are 32- or 64-bit, and the node reads either. - **`dataflow.yml`** — Example dataflow: a webcam and a one-shot caption feeding the viewer, with `strict_types: true`. Note the `output_types:` on the two `git:`-sourced nodes — their own manifests are not injected, so without those annotations strict validation fails on an untyped upstream. `bbox` is left unwired on purpose; every bbox source is a detector, and wiring one would put a model download in front of a webcam preview. - **`.gitea/workflows/validate.yml`** — CI gate running `dora validate` on the dataflow on push and pull request. Needs no camera and no display. diff --git a/README.md b/README.md index 2f7e0e2..24017a7 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ nodes: git: ssh://git@gitea.liria.cl:5001/liria/dora-plot.git tag: v0.1.0 build: pip install . - path: opencv-plot + path: dora-plot inputs: image: camera/image bbox: detector/bbox @@ -55,7 +55,7 @@ the camera and the viewer: - bbox - id: plot - path: opencv-plot + path: dora-plot build: pip install . inputs: image: camera/image @@ -91,7 +91,7 @@ of that state: - An **`image`** event decodes the frame and immediately redraws: it draws every stored bbox (green rectangle plus `label, conf` text), draws the stored text at the top left, resizes to `PLOT_WIDTH`x`PLOT_HEIGHT` if both are set, and shows it in a window titled - `Dora Node: opencv-plot`. Press `q` in the window to quit. + `Dora Node: dora-plot`. Press `q` in the window to quit. - A **`bbox`** or **`text`** event only updates stored state; it is drawn on the next `image` redraw. diff --git a/dataflow.yml b/dataflow.yml index 8c4df7f..38bf7f5 100644 --- a/dataflow.yml +++ b/dataflow.yml @@ -34,7 +34,7 @@ nodes: data: std/core/v1/String - id: plot - path: opencv-plot + path: dora-plot build: pip install . inputs: image: camera/image diff --git a/dora-node.yml b/dora-node.yml index e7a6582..c47000d 100644 --- a/dora-node.yml +++ b/dora-node.yml @@ -5,14 +5,14 @@ # dataflow against it without running the node, so CI needs neither OpenCV nor # a display. apiVersion: 1 -name: opencv-plot +name: dora-plot namespace: liria description: Overlays bounding boxes, labels, and text on an image input and displays it in an OpenCV window categories: [visualization, debug] keywords: [opencv, plot, bbox, bounding-box, image, visualization, object-detection] runtime: python -entrypoint: opencv-plot +entrypoint: dora-plot # `dora build --uv` / `dora run --uv` rewrites this to `uv pip install .` and # gives the node its own managed venv under `.dora/python-envs/`, so the # dependencies it sees at runtime are the ones installed here. @@ -57,7 +57,7 @@ example: | git: ssh://git@gitea.liria.cl:5001/liria/dora-plot.git tag: v0.1.0 build: pip install . - path: opencv-plot + path: dora-plot inputs: image: camera/image bbox: detector/bbox diff --git a/opencv_plot/__init__.py b/dora_plot/__init__.py similarity index 100% rename from opencv_plot/__init__.py rename to dora_plot/__init__.py diff --git a/opencv_plot/bbox.py b/dora_plot/bbox.py similarity index 97% rename from opencv_plot/bbox.py rename to dora_plot/bbox.py index d5d1c18..d6ea2a3 100644 --- a/opencv_plot/bbox.py +++ b/dora_plot/bbox.py @@ -2,7 +2,7 @@ import numpy as np -from opencv_plot.plot import Bboxes +from dora_plot.plot import Bboxes def parse(value, bbox_format: str) -> Bboxes: diff --git a/opencv_plot/decode.py b/dora_plot/decode.py similarity index 100% rename from opencv_plot/decode.py rename to dora_plot/decode.py diff --git a/opencv_plot/main.py b/dora_plot/main.py similarity index 95% rename from opencv_plot/main.py rename to dora_plot/main.py index b68de3d..3cc414b 100644 --- a/opencv_plot/main.py +++ b/dora_plot/main.py @@ -9,8 +9,8 @@ import os from dora import Node -from opencv_plot import bbox, decode -from opencv_plot.plot import Plot +from dora_plot import bbox, decode +from dora_plot.plot import Plot def main() -> None: @@ -59,7 +59,7 @@ def _parse_args() -> argparse.Namespace: ) parser.add_argument( "--name", - default="opencv-plot", + default="dora-plot", help="The name of the node in the dataflow, used when running as a dynamic node.", ) parser.add_argument( diff --git a/opencv_plot/plot.py b/dora_plot/plot.py similarity index 98% rename from opencv_plot/plot.py rename to dora_plot/plot.py index 67e0dc3..2063bd8 100644 --- a/opencv_plot/plot.py +++ b/dora_plot/plot.py @@ -5,7 +5,7 @@ from dataclasses import dataclass, field import cv2 import numpy as np -WINDOW = "Dora Node: opencv-plot" +WINDOW = "Dora Node: dora-plot" GREEN = (0, 255, 0) WHITE = (255, 255, 255) FONT = cv2.FONT_HERSHEY_SIMPLEX diff --git a/pyproject.toml b/pyproject.toml index f14d922..a02a52e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "opencv-plot" +name = "dora-plot" version = "0.1.0" description = "Dora node that overlays bounding boxes and text on an image and displays it in an OpenCV window" readme = "README.md" @@ -21,7 +21,7 @@ dependencies = [ ] [project.scripts] -opencv-plot = "opencv_plot.main:main" +dora-plot = "dora_plot.main:main" [dependency-groups] dev = ["pytest >= 8.1", "ruff >= 0.9"] @@ -31,7 +31,7 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] -packages = ["opencv_plot"] +packages = ["dora_plot"] [tool.ruff.lint] extend-select = ["D", "I", "N", "RET", "UP"] diff --git a/tests/test_opencv_plot.py b/tests/test_dora_plot.py similarity index 97% rename from tests/test_opencv_plot.py rename to tests/test_dora_plot.py index 948d32d..17c290e 100644 --- a/tests/test_opencv_plot.py +++ b/tests/test_dora_plot.py @@ -7,8 +7,8 @@ import numpy as np import pytest from PIL import Image -from opencv_plot import bbox, decode -from opencv_plot.plot import Bboxes, Plot +from dora_plot import bbox, decode +from dora_plot.plot import Bboxes, Plot WIDTH, HEIGHT = 12, 8 diff --git a/uv.lock b/uv.lock index e4652fe..00d0b62 100644 --- a/uv.lock +++ b/uv.lock @@ -15,6 +15,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "dora-plot" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "dora-rs" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "numpy", version = "2.5.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "opencv-python" }, + { name = "pillow" }, + { name = "pillow-avif-plugin" }, + { name = "pyarrow" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "dora-rs", specifier = ">=1.0.1" }, + { name = "numpy", specifier = ">=2.0" }, + { name = "opencv-python", specifier = ">=4.9" }, + { name = "pillow", specifier = ">=10.4" }, + { name = "pillow-avif-plugin", specifier = ">=1.4" }, + { name = "pyarrow", specifier = ">=17.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.1" }, + { name = "ruff", specifier = ">=0.9" }, +] + [[package]] name = "dora-rs" version = "1.0.1" @@ -206,42 +242,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/0b/b12a2df5d1b774bd9007a6fdff9381145b6223d37f11afc9c37ab0efd9a1/numpy-2.5.3-cp315-cp315t-win_arm64.whl", hash = "sha256:befa1ae5bd6030b3f512b43ff3fa5290bbed6b84411a44244b14adf835f5b89d", size = 10850807, upload-time = "2026-09-06T16:27:43.868Z" }, ] -[[package]] -name = "opencv-plot" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "dora-rs" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "numpy", version = "2.5.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "opencv-python" }, - { name = "pillow" }, - { name = "pillow-avif-plugin" }, - { name = "pyarrow" }, -] - -[package.dev-dependencies] -dev = [ - { name = "pytest" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "dora-rs", specifier = ">=1.0.1" }, - { name = "numpy", specifier = ">=2.0" }, - { name = "opencv-python", specifier = ">=4.9" }, - { name = "pillow", specifier = ">=10.4" }, - { name = "pillow-avif-plugin", specifier = ">=1.4" }, - { name = "pyarrow", specifier = ">=17.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.1" }, - { name = "ruff", specifier = ">=0.9" }, -] - [[package]] name = "opencv-python" version = "5.0.0.93"