33. CLI with Rich Output

Chapter 33 of 36 · 15 min

Standard CLI output works, but for complex pipelines you want tables, progress indicators, syntax highlighting, and visual structure. The rich library makes this approachable.

Building a polished CLI:

from rich.console import Console
from rich.table import Table
from rich.progress import track, Progress, SpinnerColumn, TextColumn, BarColumn
from rich.panel import Panel
from rich.syntax import Syntax
import time

console = Console()

# Styled output
console.print("[bold blue]Document Processing Pipeline[/bold blue]")
console.print("[dim]Starting at 2024-01-15 14:30:00[/dim]\n")

# Progress bar
def process_documents(docs):
    for i, doc in enumerate(docs):
        time.sleep(0.1)  # Simulate work
        yield i, doc

docs = [f"doc_{i}.txt" for i in range(20)]

with Progress(
    SpinnerColumn(),
    TextColumn("[progress.description]{task.description}"),
    BarColumn(),
    TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
    console=console
) as progress:
    task = progress.add_task("[cyan]Processing documents...", total=len(docs))
    
    for i, doc in process_documents(docs):
        progress.update(task, advance=1, description=f"[cyan]{doc}")

# Table output
def show_results(results):
    table = Table(title="Processing Results")
    table.add_column("Document", style="cyan", no_wrap=True)
    table.add_column("Words", justify="right", style="green")
    table.add_column("Status", style="yellow")
    
    for doc, words, status in results:
        status_style = "green" if status == "success" else "red"
        table.add_row(doc, str(words), f"[{status_style}]{status}[/{status_style}]")
    
    console.print(table)

results = [
    ("doc_1.txt", 1542, "success"),
    ("doc_2.txt", 892, "success"),
    ("doc_3.txt", 0, "failed"),  # Read error, maybe
]

show_results(results)

# Code display
code = '''
result = {"status": "success", "docs_processed": 18}
return result
'''
syntax = Syntax(code, "python", theme="monokai", line_numbers=True)
console.print(Panel(syntax, title="Example Output", expand=False))

The rich library auto-detects terminal capabilities and degrades gracefully on non-TTY outputs (important when piping to files). track() for simple progress bars, Progress() context manager for complex multi-task tracking.

Local verification checkpoint

Run the smallest example from this chapter in a local workspace and record the package version, runtime, data path, and observed output. If the result depends on model size, vector count, CPU/GPU backend, or available memory, note that constraint beside the exercise so the lesson remains reproducible.

EXERCISE

Create a CLI using rich that shows a progress bar for processing fake "embeddings" (just time.sleep), then displays a table with document name, embedding dimension, and processing time. Add a styled panel at the end with summary statistics.