Skip to content

feat(cli): rewrite CLI in Python with Typer and Rich#18

Merged
jcardozo-eth merged 18 commits intomainfrom
chore/cli-python-rewrite
Feb 18, 2026
Merged

feat(cli): rewrite CLI in Python with Typer and Rich#18
jcardozo-eth merged 18 commits intomainfrom
chore/cli-python-rewrite

Conversation

@jcardozo-eth
Copy link
Copy Markdown
Member

Summary

Python CLI for DAP built on Typer and Rich, with ETH Zurich branded terminal output, grouped help, tool version caching, and a full test suite. Replaces the previous Go implementation; simplifies the Nix flake and CI accordingly.

CLI features

Command surface

Four command groups, accessible via dap <command> or dap k8s <subcommand>:

Group Commands Purpose
Development test, lint, typecheck, check Run quality checks (--scope core/cli/all)
Environment welcome, tools, env, clean, reset Manage the local dev environment
Hints uv, dagster, direnv Quick-reference cards for shell tools
Infrastructure k8s up/down/restart/status/logs/shell Kubernetes lifecycle via Helm
  • dap --help uses a custom GroupedCommands class that organizes commands under section headers instead of a flat list
  • dap welcome displays the DAP-O logo, project info, and detected tool versions
  • dap dev check --scope cli runs only CLI checks (ruff + pytest); --scope core runs only pipeline checks; default runs both

Themed output (theme.py)

All output goes through a centralized Rich Console (writing to stderr) with:

  • ETH Zurich brand palette — Blue, Petrol, Green, Bronze, Red, Grey — each with light-background and dark-background variants selected automatically (via COLORFGBG detection or DAP_THEME=light|dark override)
  • Semantic stylessuccess (green), error (red), warning (bronze), info (petrol), title (bold blue), hint (grey), command (bold blue)
  • Standard symbolsOK (checkmark), FAIL (cross), WARN (exclamation), ARROW (right arrow), DASH (em dash)
  • 2-space indent on all output lines for visual consistency
  • NO_COLOR and CI support — color disabled automatically in CI or when NO_COLOR is set

Tool version cache (utils/cache.py)

dap welcome and dap tools detect versions of Python, uv, kubectl, Helm, etc. Results are cached to a JSON file with a configurable TTL (default 1 hour), so repeated runs skip the subprocess calls. Cache auto-invalidates on TTL expiry and handles file corruption gracefully.

Developer experience

The dap CLI gives every operator of this repository — human developers, coding agents, and CI pipelines — a single, predictable interface for common tasks.

  • Onboarding. dap welcome shows installed tools, active versions, and environment health at a glance. Hint commands (dap uv, dap dagster, dap direnv) provide cheat sheets without leaving the terminal.

  • Common tasks. dap check runs lint, typecheck, and test in sequence with live progress and clear pass/fail output. dap k8s up encodes a multi-step workflow so the right flags and ordering are always applied.

  • Agents and automation. NO_COLOR and CI detection ensure clean output in non-interactive contexts. CI calls the same commands developers run locally, so there is one definition of "passing" everywhere.

Build and infrastructure changes

  • UV workspace. The CLI lives at cli/ as a workspace member. uv sync installs both the pipeline and CLI in one step — no separate build artifact.
  • Nix flake. Reduced from 4 devshells + a sub-flake to 2 devshells (default, minimal). Go toolchain removed.
  • CI. New setup-nix-env reusable composite action shared by ci.yml and cli.yml. GoReleaser release workflow removed.
  • Helm. values-local.yaml gains readiness and startup probes for the webserver.

Testing

dap check --scope cli runs the full CLI quality pipeline: ruff (linting and format checking), mypy (static type checking), and pytest (unit and behavioral tests). This is the same command used in CI.

The test suite (~430 lines, 3 files) uses typer.testing.CliRunner and unittest.mock:

  • test_commands.py — structural tests (all commands registered, help text present) and behavioral tests for dev/env/hints commands
  • test_k8s.py — unit tests for helper functions, behavioral tests for down, status, and wait logic
  • test_cache.py — roundtrip serialization, TTL invalidation, corruption recovery, integration with welcome

Terminal output

dap welcome

  ██████╗  █████╗ ██████╗          ██████╗
  ██╔══██╗██╔══██╗██╔══██╗        ██╔═══██╗
  ██║  ██║███████║██████╔╝ █████╗ ██║   ██║
  ██║  ██║██╔══██║██╔═══╝  ╚════╝ ██║   ██║
  ██████╔╝██║  ██║██║             ╚██████╔╝
  ╚═════╝ ╚═╝  ╚═╝╚═╝              ╚═════╝
  Data Archive Pipeline (DAP) — Orchestrator
  ETH Library Zurich

  Tools
  python         3.12.12
  uv             0.9.29
  dap            0.1.0
  dagster        1.12.14
  ruff           0.15.1
  mypy           1.19.1
  pytest         9.0.2

  Environment
  nix flake      /home/runner/work/data-assets-pipeline
  python venv    /home/runner/work/data-assets-pipeline/.venv
  DAGSTER_HOME   /home/runner/work/data-assets-pipeline/.dagster

  Quick Start
  dap test       Run tests (pytest)
  dap check      Run all quality checks (lint, typecheck, test)
  dap tools      Show installed tool versions

  Run 'dap --help' for all commands

dap --help

Usage: dap [OPTIONS] COMMAND [ARGS]...

  Developer tools for the Data Archive Pipeline (DAP) Orchestrator.

Options:
  -V, --version  Show version and exit.
  --help         Show this message and exit.

Development:
  test       Run tests with pytest.
  lint       Check code style and formatting with ruff.
  typecheck  Run type checking with mypy.
  check      Run all quality checks (ruff, mypy, pytest).

Environment:
  welcome  Show welcome banner and environment info.
  tools    Show installed tool versions and paths.
  env      Show environment paths and status.
  clean    Remove .venv and caches.
  reset    Clean and reinstall dependencies.

Hints:
  uv       Show how to use uv directly.
  dagster  Show how to use dagster and dg directly.
  direnv   Show how to use direnv directly.

Infrastructure:
  k8s  Kubernetes operations.

dap check --scope cli

  → Lint (CLI) — checking code style
    ruff check cli/dap_cli
  ✓ Lint (CLI) — checking code style — passed

  → Lint (CLI) — checking formatting
    ruff format --check cli/dap_cli
  ✓ Lint (CLI) — checking formatting — passed

  → Typecheck (CLI) — running mypy
    mypy cli/dap_cli
  ✓ Typecheck (CLI) — running mypy — passed

  → Test (CLI) — running pytest
    pytest cli/tests
  ✓ Test (CLI) — running pytest — passed

  ✓ All checks passed (CLI)

Remove the gomod2nix pre-commit hook as part of the CLI rewrite
from Go to Python.
Remove the entire Go-based CLI implementation (Cobra + Lipgloss)
including commands, internal packages, Go module files, Nix flake,
goreleaser config, and package.nix. The CLI is being rewritten in
Python with Typer + Rich.
Replace the Go CLI with a Python implementation using Typer 0.15+
and Rich 13+. The new CLI is a UV workspace member (`cli/`) with
entry point `dap = "dap_cli.app:main"`.

Commands implemented:
- dev: test, lint, typecheck, check (with --scope core|cli|all)
- env: welcome, tools, env, clean, reset
- hints: uv, dagster, direnv (usage guidance)
- k8s: up, down, restart, status, logs, shell

Features:
- ETH Zurich brand colours with light/dark terminal detection
- Centralized Rich console with NO_COLOR and CI support
- Grouped help output with custom TyperGroup
- Comprehensive test suite with mocked subprocess calls
Add `cli/` as a UV workspace member so the Python CLI is installed
alongside the pipeline. Add `dagster-dg-cli` dependency and `tool.dg`
configuration for project-scoped Dagster CLI support.
Remove the dap-cli flake input, Go packages, and gomod2nix overlay.
Consolidate from four shells (default, minimal, k8s, cli-dev) to two
(default with k8s tools, minimal with just Python + uv). The CLI is
now a Python package installed by uv, not a Nix-built Go binary.
Add a composite action that installs Nix with Determinate Systems
installer, enables magic-nix-cache, and exports the devshell
environment to GitHub Actions via direnv.
Simplify CI and CLI workflows to use the new composite action and
run `dap check --scope core` / `dap check --scope cli` instead of
raw nix develop commands. Remove the Go-based goreleaser release
workflow (no longer needed).
Add readinessProbe and startupProbe to the Dagster webserver in
local values to prevent routing traffic before the server is ready
and allow sufficient time for initial startup.
Update README with new command reference, dev toolchain overview,
environment variables (DAP_THEME, NO_COLOR), and Python project
structure. Remove all Go references (Go prereq, goreleaser, Cobra,
Charmbracelet). Rewrite cli/CONTRIBUTING.md with Typer/Rich
architecture, TUI conventions, and Python testing patterns.
Cache tool version results in `.venv/.dap-tool-cache.json` with a
SHA-256 fingerprint of uv.lock, flake.lock, and flake.nix. The
cache is invalidated when any of these files change and cleared by
`dap clean`. Removes the `--quick` flag from `dap welcome` since
cached lookups are effectively instant.
Replace the `.dev/scripts/uv-sync.sh` wrapper with a direct
`uv sync --extra dev --all-packages` call.
Auto-fetch nix-direnv if not installed globally to avoid slow
flake re-evaluation on every shell entry.
Remove the main-only branch filter so CLI quality checks run on
every push that touches cli/, not just main and pull requests.
Include .github/workflows/cli.yml in the paths filter so workflow
edits themselves trigger the pipeline.
Comment thread cli/dap_cli/commands/k8s.py Fixed
Comment thread cli/tests/test_cache.py Fixed
Comment thread cli/dap_cli/utils/cache.py Fixed
@jcardozo-eth jcardozo-eth merged commit 8cd0565 into main Feb 18, 2026
7 of 9 checks passed
@jcardozo-eth jcardozo-eth deleted the chore/cli-python-rewrite branch February 19, 2026 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant