f700102067
examples/gui/ is a full Qt + open3d application (30 modules, 4,815 lines) rather than an example, and its proper home is the orisys-studio application. The move is planned but not started, so this records the plan rather than performing any of it. What the plan establishes, so the work does not have to be re-derived: - src/orisys/ imports no gui/viz/examples module, verified by AST rather than grep. The dependency is one-way, so the GUI can leave without a library change. The single apparent hit is `from .pipeline import ...` in src/orisys/__init__.py, which is the SDK's own module. - examples/viz/ is shared and cannot follow the GUI wholesale: it mixes open3d renderers with toolkit-independent helpers that examples/pipeline/service.py and tests/test_contact_arrow_scale.py depend on. It has to be split. - The real coupling is inverted and lives in the tests: tests/test_qt_viewer_backend.py imports examples/gui, and tests/conftest.py deliberately puts examples/ ahead of build/ because both define a package named `gui`. Removing the GUI means re-deriving that guard, not deleting it blindly. - UVMeshViewer and friends are in src/orisys/finger/__init__.__all__, so removing them is a breaking change to a released API and needs a deprecation release first. It must not be folded into a code move. - The `examples/` directory must keep existing in the packaged layout even after gui/ leaves it: src/orisys/configs.py anchors its run-root detection on a sibling examples/ folder. Also updates examples/README.md to say "lives here for now" instead of "is moving out", so nothing reads as work in progress. The GUI itself is untouched, and the only guidance offered is that new SDK work should not build on it.
140 lines
8.1 KiB
Markdown
140 lines
8.1 KiB
Markdown
---
|
||
kind: reference
|
||
---
|
||
|
||
# Plan: move the GUI out of the SDK into `orisys-studio`
|
||
|
||
Status: **planned, then postponed (2026-09-30).** Nothing here is in progress. This document
|
||
records what would move, what would stay, and the one coupling that makes the move non-trivial, so
|
||
that the work can be picked up without re-deriving it. It is a plan, not a description of current
|
||
behaviour — everything described below is still in the SDK exactly as listed.
|
||
|
||
## Why
|
||
|
||
`examples/gui/` is not an example. It is a full Qt + open3d + pyqtgraph application — 30 modules,
|
||
4,815 lines — that ships inside the SDK wheel. The GUI belongs to the `orisys-studio` application,
|
||
which already exists for that purpose. Leaving it in the SDK means the SDK ships, versions and
|
||
installs an application it is not responsible for.
|
||
|
||
## Current state
|
||
|
||
| Path | Modules | Lines | What it is |
|
||
|---|---|---|---|
|
||
| `examples/gui/` | 30 | 4,815 | The application: `viewer2d/`, `viewer3d/`, `widgets/`, `app.py`, `log_config.py` |
|
||
| `examples/viz/` | 11 | 2,298 | **Shared** drawing/rendering helpers — see the coupling below |
|
||
| `examples/pipeline/` | 6 | 577 | Sensor service, CSV recorder, profiling. **SDK support code, not GUI** |
|
||
|
||
### Good news: the SDK core does not depend on the GUI
|
||
|
||
Verified by AST, not by grep: **no module under `src/orisys/` imports `gui`, `viz`, `pipeline` or
|
||
`examples`.** The only match is `src/orisys/__init__.py` importing `orisys.pipeline`, which is the
|
||
SDK's own module. The dependency runs one way, so the GUI can leave without touching the library.
|
||
|
||
Two apparent hits are prose, not code: `src/orisys/configs.py` mentions `examples/` in a docstring
|
||
about run-root layout, and `export_sensors.py` has an `Examples::` docstring section. The
|
||
`configs.py` anchor is a real behavioural dependency to preserve — the run-root heuristic keys off
|
||
a sibling `examples/` directory, so that directory must keep existing in the packaged layout even
|
||
after `gui/` leaves it.
|
||
|
||
### The coupling: `viz/` is shared, so it cannot simply follow the GUI
|
||
|
||
```
|
||
examples/gui/ ──uses──▶ examples/viz/ ──uses──▶ orisys (SDK)
|
||
examples/pipeline/service.py ──uses──▶ examples/viz/
|
||
tests/test_contact_arrow_scale.py ──uses──▶ examples/viz/
|
||
```
|
||
|
||
`examples/pipeline/service.py` and a test depend on `viz`, and `viz` is a mix: `mesh_camera.py`,
|
||
`contact_arrow.py`, `flow_arrow.py` and `offscreen_mesh.py` are open3d rendering helpers, while
|
||
`render_2d.py`, `recording.py`, `signal_filters.py` and `force_charts.py` are toolkit-independent.
|
||
**Moving `viz/` wholesale would break `examples/pipeline/`.** It has to be split, not moved.
|
||
|
||
### The real coupling is in the tests, and it is inverted
|
||
|
||
`tests/test_qt_viewer_backend.py` imports `examples/gui` directly, and `tests/conftest.py` inserts
|
||
`EXAMPLES_ROOT` into `sys.path` with a guard whose stated reason is that **`examples/gui` must win
|
||
over `build/gui`, because both are packages named `gui`**. So the SDK's test suite currently
|
||
depends on the GUI application being present and on a name-resolution guard existing for it.
|
||
|
||
This is the inversion to fix: the SDK must not depend on the GUI.
|
||
|
||
Two related facts:
|
||
|
||
- `examples/gui/` contains committed `__pycache__` directories (`adapter.cpython-310.pyc`,
|
||
`cpython-313.pyc`, …) — build artefacts tracked alongside source.
|
||
- `tests/test_wheel_contents.py` and `tests/test_pyproject.py` assert on what the wheel bundles, so
|
||
they will need updating when the `gui/**/*.py` bundle pattern goes.
|
||
|
||
## What moves, what stays
|
||
|
||
**Moves to `orisys-studio`:**
|
||
|
||
- `examples/gui/**` — the whole application, as the single home for GUI code.
|
||
- `examples/finger_pipeline_3dview.py` — a 91-line launcher for the dashboard; its only purpose is
|
||
to start the GUI, so it belongs with the GUI.
|
||
- The open3d rendering half of `examples/viz/`: `contact_arrow.py`, `flow_arrow.py`,
|
||
`mesh_camera.py`, `offscreen_mesh.py`, plus the open3d-dependent `__init__` re-exports.
|
||
- `tests/test_qt_viewer_backend.py` — it tests the GUI, so it moves with the GUI.
|
||
|
||
**Stays in the SDK:**
|
||
|
||
- `examples/pipeline/` — SDK support code (sensor service, CSV recording, profiling).
|
||
- `examples/viz/` toolkit-independent half: `render_2d.py`, `recording.py`, `signal_filters.py`,
|
||
`force_charts.py` — needed by `examples/pipeline/service.py`.
|
||
- `examples/plot_data.py` — uses pyqtgraph for force charts only; 96 lines. Decide separately
|
||
whether it follows the GUI; it is the one remaining example with a Qt dependency after the move.
|
||
- `src/orisys/finger/viewer.py` (`UVMeshViewer`) — **see the deprecation note below.**
|
||
|
||
## The public-API problem, handled separately
|
||
|
||
`UVMeshViewer`, `init_uv_mesh_viewer` and `update_uv_mesh_viewer` are exported in
|
||
`src/orisys/finger/__init__.py`'s `__all__`. **Removing them is a breaking change to a released
|
||
API**, so it must not be bundled into a code move:
|
||
|
||
1. Release with them present and documented `DeprecationWarning`s emitted on construction.
|
||
2. Remove them at the next major version, with the release notes naming the replacement.
|
||
|
||
The audit (`docs/api-audit.md`) already lists `UVMeshViewer` among the surface that is used by
|
||
examples and absent from the reference.
|
||
|
||
## Sequence, lowest risk first
|
||
|
||
| # | Step | Risk | Notes |
|
||
|---|---|---|---|
|
||
| 1 | Add `docs/plan-gui-extraction.md` (this file) | none | Done |
|
||
| 2 | Delete the committed `__pycache__` under `examples/gui/` and add it to `.gitignore` | none | Pure hygiene; ship independently |
|
||
| 3 | Tag the SDK at the commit whose `examples/gui` is known-good, so the studio move has a pinned source | none | A tag, not a submodule or subtree |
|
||
| 4 | In `orisys-studio`: import `examples/gui` + the open3d half of `viz` as its own provenance-stated change, reconciling against its existing viewer code | **medium** | The studio repo already has viewer code; this is a merge decision, not a copy |
|
||
| 5 | In the SDK: move `tests/test_qt_viewer_backend.py` out, and simplify the `conftest.py` guard | **medium** | The guard exists for `gui`; with `gui` gone, `EXAMPLES_ROOT` may still be needed for `viz`/`pipeline`. Re-derive, do not guess |
|
||
| 6 | In the SDK: retire `examples/gui/`, `finger_pipeline_3dview.py`, and the moved `viz` modules | low once 4 and 5 land | |
|
||
| 7 | Update the bundle patterns in `pyproject.toml` (drop `gui/**/*.py`, adjust `viz/**`) and the wheel tests | low | `test_wheel_contents.py`, `test_pyproject.py` |
|
||
| 8 | Update `examples/README.md` and the SDK reference to stop pointing at the dashboard | low | The README already says the GUI is moving |
|
||
| 9 | Deprecate `UVMeshViewer` in a release; remove at the next major | low | Separate release cycle |
|
||
|
||
Steps 2 and 3 are safe to do immediately and independently. Steps 4–5 are the actual move and need
|
||
both repositories. Nothing here requires a library behaviour change, which is what makes the move
|
||
tractable.
|
||
|
||
## Open questions for the studio side
|
||
|
||
- **Merge or adopt?** `orisys-studio` already has its own viewer. If its code is the descendant of
|
||
this one, take the SDK copy only where it is ahead; otherwise choose one and delete the other.
|
||
This must be decided before step 4, because the answer changes what gets imported.
|
||
- **Do the SDK's 2D and 3D viewers need to keep working headless for CI?** `examples/viz` contains
|
||
offscreen rendering used to produce evidence images. If any SDK or sensor-design workflow depends
|
||
on that, the offscreen half may need to stay reachable from the SDK even after the app moves.
|
||
- **Does `plot_data.py` follow the GUI?** It is an example, not an application, and it is the last
|
||
Qt-dependent file in `examples/`.
|
||
|
||
## Acceptance criteria
|
||
|
||
- [ ] `src/orisys/` still imports no `gui`/`viz`/`examples` module (re-run the AST check).
|
||
- [ ] The SDK test suite passes with `examples/gui/` absent.
|
||
- [ ] No module named `gui` ships in the wheel; `test_wheel_contents.py` asserts it.
|
||
- [ ] `examples/pipeline/service.py` and `tests/test_contact_arrow_scale.py` still import their
|
||
`viz` dependencies.
|
||
- [ ] `UVMeshViewer` is either deprecated-but-present or removed by an explicit major-version
|
||
decision — never dropped silently in a move.
|
||
- [ ] The `examples/` sibling directory still exists in the packaged layout, because
|
||
`configs.py`'s run-root anchor depends on it.
|