Skip to content

Add blueye logs command for listing and downloading dive logs - #220

Merged
johannesschrimpf merged 10 commits into
jp-pino/bundle-model-clifrom
jp-pino/logs-cli
Aug 10, 2026
Merged

Add blueye logs command for listing and downloading dive logs#220
johannesschrimpf merged 10 commits into
jp-pino/bundle-model-clifrom
jp-pino/logs-cli

Conversation

@jp-pino

@jp-pino jp-pino commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a blueye logs built-in to the CLI (stacked on #219's command registry), surfacing the documented drone.logs workflow from the terminal — including first-party conversion to Foxglove's .mcap format, which retires the example converter script.

  • blueye logs list — table of the drone's binary logs (name, time, max depth, size, dive flag), sorted descending alphabetically (newest first).
  • blueye logs download [NAME ...] [--latest N | --all] [-o DIR] — downloads .bez files; unknown names error with the available names listed.
  • --mcap — converts each downloaded log to a Foxglove-ready .mcap next to the .bez. The converter (commands/logs/mcap.py) is adapted from the former example script, keeping its two-pass timestamp anchoring so logs where the drone's clock was set mid-dive still get a continuous timeline.
  • blueye logs convert <file.bez ...> [-o DIR] — converts already-downloaded logs locally, no drone connection needed.
  • Filters--dives-only, --since YYYY-MM-DD, --until YYYY-MM-DD shared by list, download, and the interactive view.
  • Interactive mode — bare blueye logs on a terminal opens a single scrollable multi-select table (column-aligned rows under one header, type-to-filter via questionary's search filter, sorted newest first), then asks for a destination and whether to convert to .mcap. An explicit instruction string works around questionary 2.1.1 displaying <ctrl-a> for both toggle-all and invert (the real invert binding is ctrl-i/tab).
  • Observer connection, no SDK changes — drone actions connect with connect_as_observer=True (no control taken, released on exit); convert never connects. Unreachable drones fail gracefully with exit 1.
  • The --drone-ip/--timeout parent parser and the transport-failure→CliError translation live in commands/_common.py, shared with the models command.
  • Example retired: examples/foxglove_bez_to_mcap.py is deleted in favor of the first-party command; mcap-protobuf-support leaves the [examples] extra (stays in [cli]), and the Foxglove guide now walks through the CLI instead of cloning the repo.

Testing

  • 33 hermetic tests for the command (list/download/convert flows, filters incl. date boundaries and bad-date errors, descending sort, interactive single-table flow via the prompter seam, drop of the duplicated pre-table, exit codes, per-command gates, use_search_filter wiring) — 451 total, black clean, mkdocs build clean.
  • Verified against the bench drone: filtered + sorted list; download --latest 1 --mcap produced a valid .mcap; local blueye logs convert on a downloaded .bez produced a valid 1.19M-message .mcap (MCAP magic checked); unreachable-address runs exit 1 with the friendly message.

Docs

docs/cli.md gains the logs section (incl. convert and the filter flags), the quick start shows blueye logs download --latest 1, the logs guide links the CLI page, and the Foxglove guide is rewritten around the one-step CLI flow.

🤖 Generated with Claude Code

Surfaces the documented drone.logs workflow as a CLI built-in:

- `blueye logs list` — table of the drone's binary logs (name, time,
  max depth, size, dive flag).
- `blueye logs download [NAME ...] [--latest N | --all] [-o DIR]` —
  downloads .bez files; unknown names error listing what is available.
- Bare `blueye logs` on a terminal opens an interactive picker: the
  table plus a checkbox multi-select and a destination prompt. The
  Prompter seam gains a checkbox method (questionary.checkbox
  interactively; a CliError naming the flags non-interactively).
- Connects to the drone as an observer (connect_as_observer=True), so
  no control is taken and no SDK changes were needed; an unreachable
  drone fails with the friendly message and exit 1. The connection is
  released on exit.
- The --drone-ip/--timeout parent parser and the failure-translation
  helper are lifted into commands/_common.py, now shared with the
  models command.

Verified against the bench drone (list + `--latest 1` downloaded a
real 2.5 MiB .bez) and an unreachable address. +14 tests (432 total);
docs gain a "From the command line" section in the logs guide.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.94585% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.34%. Comparing base (92119dc) to head (d884faa).

Files with missing lines Patch % Lines
blueye/sdk/cli/commands/logs/command.py 95.95% 7 Missing ⚠️
blueye/sdk/cli/commands/models/command.py 77.77% 4 Missing ⚠️
blueye/sdk/cli/prompts.py 91.89% 3 Missing ⚠️
Additional details and impacted files
@@                     Coverage Diff                      @@
##           jp-pino/bundle-model-cli     #220      +/-   ##
============================================================
+ Coverage                     83.38%   84.34%   +0.96%     
============================================================
  Files                            32       36       +4     
  Lines                          3214     3463     +249     
============================================================
+ Hits                           2680     2921     +241     
- Misses                          534      542       +8     
Flag Coverage Δ
macos-latest_3.10 84.17% <94.94%> (+0.97%) ⬆️
macos-latest_3.11 84.08% <94.94%> (+0.98%) ⬆️
macos-latest_3.12 84.08% <94.94%> (+0.98%) ⬆️
macos-latest_3.13 84.08% <94.94%> (+0.98%) ⬆️
macos-latest_3.14 84.20% <94.94%> (+0.97%) ⬆️
ubuntu-latest_3.10 84.17% <94.94%> (+0.97%) ⬆️
ubuntu-latest_3.11 84.08% <94.94%> (+0.98%) ⬆️
ubuntu-latest_3.12 84.08% <94.94%> (+0.98%) ⬆️
ubuntu-latest_3.13 84.08% <94.94%> (+0.98%) ⬆️
ubuntu-latest_3.14 84.20% <94.94%> (+0.97%) ⬆️
windows-latest_3.10 84.14% <94.94%> (+0.97%) ⬆️
windows-latest_3.11 84.06% <94.94%> (+0.98%) ⬆️
windows-latest_3.12 84.06% <94.94%> (+0.98%) ⬆️
windows-latest_3.13 84.06% <94.94%> (+0.98%) ⬆️
windows-latest_3.14 84.17% <94.94%> (+0.97%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

`blueye logs download ... --mcap` converts each downloaded .bez to a
Foxglove-ready .mcap next to it; the interactive picker offers the same
conversion after selecting logs. The converter
(commands/logs/mcap.py) is adapted from
examples/foxglove_bez_to_mcap.py: a first LogStream pass anchors the
dive start time (last record's wall clock minus its monotonic delta, so
logs where the clock was set mid-dive stay continuous), a second pass
writes every protobuf message via mcap_protobuf.writer.

mcap-protobuf-support joins the [cli] extra (and dev group); the --mcap
path gates on it at runtime with the standard install guidance, so the
rest of the logs command works without it.

Verified against the bench drone: `blueye logs download --latest 1
--mcap` produced a valid 8.5 MB .mcap (217k messages, correct MCAP
magic) from a real dive log. +6 tests incl. a real protobuf-built .bez
round trip (438 total); the Foxglove doc gains a one-step
download-and-convert tip.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jp-pino
jp-pino requested review from Copilot and sindrehan July 10, 2026 11:09
@jp-pino jp-pino self-assigned this Jul 10, 2026
@jp-pino jp-pino added the enhancement New feature or request label Jul 10, 2026
@jp-pino jp-pino added this to the Blunux v5.1 milestone Jul 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new blueye logs CLI command suite to list and download the drone’s binary dive logs, with an optional .bez.mcap conversion flow intended for Foxglove, while reusing existing SDK log metadata and keeping the drone connection observer-only.

Changes:

  • Introduces blueye logs list / blueye logs download (plus interactive blueye logs) backed by shared connection/error helpers.
  • Adds an MCAP conversion utility and wires it behind a runtime dependency gate (--mcap).
  • Expands documentation and adds a comprehensive new hermetic test module for the logs command behavior.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
uv.lock Adds mcap-protobuf-support to locked optional CLI and dev dependency sets.
pyproject.toml Adds mcap-protobuf-support to [project.optional-dependencies].cli and dev.
tests/test_cli_logs_command.py Adds end-to-end CLI tests for logs list/download, interactive flow, and MCAP conversion gating.
docs/logs/listing-and-downloading.md Documents CLI-based log listing/downloading and interactive usage.
docs/logs/foxglove-bez-to-mcap.md Adds a one-step CLI tip for downloading and converting to .mcap.
blueye/sdk/cli/prompts.py Extends the prompting seam with a checkbox() prompt used by interactive log selection.
blueye/sdk/cli/commands/models/command.py Refactors shared drone options and friendly error translation into _common.
blueye/sdk/cli/commands/logs/mcap.py Adds .bez.mcap converter (two-pass anchor strategy).
blueye/sdk/cli/commands/logs/command.py Implements logs subcommands, interactive selection, download, and optional conversion.
blueye/sdk/cli/commands/logs/init.py Registers the new logs command in the CLI command registry.
blueye/sdk/cli/commands/_common.py New shared parser and error translation helpers for drone-talking commands.
blueye/sdk/cli/commands/init.py Registers logs in the built-in command list ordering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +132 to +148
def _select_downloads(args, log_files) -> list:
"""Resolve the download selection from names/--latest/--all."""
by_name = {log.name: log for log in log_files}
if args.all:
return list(log_files)
if args.latest is not None:
newest_first = sorted(log_files, key=lambda log: log.start_time, reverse=True)
return newest_first[: args.latest]
if args.names:
missing = [name for name in args.names if name not in by_name]
if missing:
available = ", ".join(sorted(by_name)) or "none"
raise CliError(
f"No log named {', '.join(missing)} on the drone (available: {available})."
)
return [by_name[name] for name in args.names]
raise CliError("Nothing selected — pass log names, --latest N, or --all.")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 44cdcad — the three selectors (names, --latest, --all) are now mutually exclusive and error with "Pass only one of log names, --latest N, or --all.", and --latest values below 1 are rejected instead of succeeding with an empty selection. Tests added for both.

jp-pino and others added 8 commits July 10, 2026 14:12
Follow-up to the review changes merged from jp-pino/bundle-model-cli:

- The logs command joins the consolidated docs/cli.md as a
  "Downloading dive logs" section (incl. --mcap); the logs guide and
  the Foxglove doc keep short pointers to the CLI page.
- The quick start gains a "Try the command line interface" section
  showcasing `blueye logs download --latest 1` with links to the CLI
  page.
- With rich/questionary in the core dependencies, the logs command
  declares requires=() (the --mcap path keeps its runtime gate);
  mcap-protobuf-support stays in the [cli] extra alongside onnx.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…example

Follow-ups on the logs command:

- New `blueye logs convert <file.bez ...> [-o DIR]` converts
  already-downloaded logs to .mcap without touching the drone (dispatch
  happens before the observer connection; same runtime mcap gate).
- Interactive view redesigned: instead of printing the full table and
  then a duplicate checkbox list, it is now a single scrollable
  multi-select table (each choice is a column-aligned row under one
  header line) with type-to-filter (questionary use_search_filter),
  sorted descending alphabetically — newest logs first. An explicit
  instruction string works around questionary 2.1.1 showing <ctrl-a>
  for both toggle-all and invert (the real invert binding is
  ctrl-i/tab).
- New --dives-only / --since / --until filters shared by list,
  download, and the interactive view; list output is sorted descending
  too.
- The example converter (examples/foxglove_bez_to_mcap.py) is retired
  in favor of the first-party command: the Foxglove doc now walks
  through `blueye logs download --latest 1 --mcap` and
  `blueye logs convert`, and mcap-protobuf-support leaves the
  [examples] extra (its only consumer).

Verified against the bench drone: filtered+sorted list, download, and a
local `blueye logs convert` producing a valid .mcap (1.19M messages).
+13 tests (451 total); docs build clean with the embed removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Works around a second questionary 2.1.1 search-filter bug (user-found):
with a filter active, ctrl-a (toggle all) and ctrl-i/tab (invert)
operated on every choice — selecting files not even in view — because
questionary's handlers iterate ic.choices instead of
ic.filtered_choices. The prompter now replaces both key bindings on the
constructed prompt with versions scoped to the visible rows: toggle-all
selects/deselects only what the filter shows, invert flips only the
visible rows, and selections hidden by the filter are left untouched.

The selection logic lives in pure helpers (_toggle_all_visible,
_invert_visible) with unit tests, plus an integration test asserting the
rebinding attaches to a real questionary prompt. +5 tests (456 total).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
prompt_toolkit raises NoConsoleScreenBufferError when questionary builds
a prompt without a console; the test now uses a pipe input and
DummyOutput app session.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Addresses the Copilot review on #220: names/--latest/--all are now
mutually exclusive instead of silently prioritized, and --latest must
be at least 1 rather than succeeding with an empty selection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@johannesschrimpf
johannesschrimpf merged commit 2a37bc6 into jp-pino/bundle-model-cli Aug 10, 2026
18 checks passed
@johannesschrimpf
johannesschrimpf deleted the jp-pino/logs-cli branch August 10, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants