DEV Community

郑沛沛
郑沛沛

Posted on

Build Beautiful CLI Tools in Python with Typer and Rich

Command-line tools are a developer's bread and butter. Python's typer and rich libraries make building them surprisingly pleasant.

Setup

pip install typer rich
Enter fullscreen mode Exit fullscreen mode

Your First CLI with Typer

# cli.py
import typer

app = typer.Typer()

@app.command()
def hello(name: str, count: int = 1):
    """Greet someone multiple times."""
    for _ in range(count):
        print(f"Hello, {name}!")

if __name__ == "__main__":
    app()
Enter fullscreen mode Exit fullscreen mode
python cli.py Alice --count 3
# Hello, Alice!
# Hello, Alice!
# Hello, Alice!

python cli.py --help
# Usage: cli.py [OPTIONS] NAME
# Greet someone multiple times.
Enter fullscreen mode Exit fullscreen mode

Typer automatically generates help text, validates types, and handles errors.

Multiple Commands

import typer
from typing import Optional

app = typer.Typer(help="Project management CLI")

@app.command()
def init(name: str, template: str = "default"):
    """Initialize a new project."""
    print(f"Creating project '{name}' with template '{template}'")

@app.command()
def build(target: str = "all", verbose: bool = False):
    """Build the project."""
    if verbose:
        print(f"Building target: {target} (verbose mode)")
    else:
        print(f"Building {target}...")

@app.command()
def deploy(env: str = typer.Option("staging", help="Target environment")):
    """Deploy to an environment."""
    confirm = typer.confirm(f"Deploy to {env}?")
    if confirm:
        print(f"Deploying to {env}...")

if __name__ == "__main__":
    app()
Enter fullscreen mode Exit fullscreen mode

Adding Rich for Beautiful Output

import typer
from rich.console import Console
from rich.table import Table
from rich.progress import track
from rich import print as rprint
import time

console = Console()
app = typer.Typer()

@app.command()
def status():
    """Show project status."""
    table = Table(title="Service Status")
    table.add_column("Service", style="cyan")
    table.add_column("Status", style="green")
    table.add_column("Uptime", style="yellow")

    table.add_row("API", "✅ Running", "14d 3h")
    table.add_row("Database", "✅ Running", "14d 3h")
    table.add_row("Cache", "⚠️ Degraded", "2h 15m")
    table.add_row("Worker", "❌ Down", "0m")

    console.print(table)

@app.command()
def process(files: list[str]):
    """Process files with a progress bar."""
    for f in track(files, description="Processing..."):
        time.sleep(0.5)  # simulate work
    rprint("[bold green]All files processed![/bold green]")

if __name__ == "__main__":
    app()
Enter fullscreen mode Exit fullscreen mode

Interactive Prompts

@app.command()
def configure():
    """Interactive configuration setup."""
    name = typer.prompt("Project name")
    version = typer.prompt("Version", default="0.1.0")
    use_docker = typer.confirm("Use Docker?", default=True)

    console.print(f"[bold]Configuration:[/bold]")
    console.print(f"  Name: [cyan]{name}[/cyan]")
    console.print(f"  Version: [cyan]{version}[/cyan]")
    console.print(f"  Docker: [cyan]{use_docker}[/cyan]")
Enter fullscreen mode Exit fullscreen mode

Error Handling with Style

@app.command()
def deploy(env: str):
    """Deploy with proper error handling."""
    valid_envs = ["staging", "production", "dev"]
    if env not in valid_envs:
        console.print(f"[bold red]Error:[/bold red] Invalid environment '{env}'")
        console.print(f"Valid options: {', '.join(valid_envs)}")
        raise typer.Exit(code=1)

    with console.status(f"[bold green]Deploying to {env}..."):
        time.sleep(3)  # simulate deployment

    console.print(f"[bold green]✅ Deployed to {env} successfully![/bold green]")
Enter fullscreen mode Exit fullscreen mode

Packaging Your CLI

# pyproject.toml
[project.scripts]
mycli = "mycli.main:app"
Enter fullscreen mode Exit fullscreen mode
pip install -e .
mycli status
mycli deploy --env production
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • Typer gives you argument parsing, validation, and help text for free
  • Rich makes terminal output beautiful with tables, progress bars, and colors
  • Use typer.confirm() for dangerous operations
  • Package with pyproject.toml for easy distribution
  • Combine both libraries for professional-grade CLI tools

Your CLI tools deserve to look as good as your web apps.

🚀 Level up your AI workflow! Check out my AI Developer Mega Prompt Pack — 80 battle-tested prompts for developers. $9.99

Top comments (0)