32. CLI Argument Parsing
Beyond click basics, sophisticated CLI tools need subcommands, chained options, validation, and user feedback.
Advanced argument handling:
import click
from click import Context
@click.group()
def cli():
"""Document intelligence CLI."""
pass
@cli.command()
@click.argument("sources", nargs=-1, type=click.Path()) # Multiple args
@click.option("--format", "-f",
type=click.Choice(["json", "yaml", "csv"]),
default="json",
help="Output format")
@click.option("--threshold", "-t",
type=float,
default=0.7,
help="Confidence threshold (0.0-1.0)")
@click.option("--workers", "-w",
type=int,
default=4,
help="Parallel workers")
def analyze(sources, format, threshold, workers):
"""Analyze documents from multiple sources."""
# Validate threshold
if not 0.0 <= threshold <= 1.0:
click.echo("Error: threshold must be between 0.0 and 1.0", err=True)
raise click.Abort()
click.echo(f"Analyzing {len(sources)} sources...")
click.echo(f"Format: {format}, Threshold: {threshold}, Workers: {workers}")
for source in sources:
click.echo(f" - {source}")
@cli.command()
@click.option("--config", "-c", type=click.Path(exists=True),
help="Config file (YAML)")
@click.pass_context
def run(ctx, config):
"""Run pipeline with optional config."""
if config:
click.echo(f"Loading config from: {config}")
else:
click.echo("Using default config")
click.echo("Running pipeline...")
# Add a second-level group
@cli.group(name="model")
def model_group():
"""Model management commands."""
pass
@model_group.command(name="list")
def model_list():
"""List available models."""
models = ["gpt-4", "gpt-3.5-turbo", "claude-3-opus"]
for m in models:
click.echo(f" - {m}")
@model_group.command()
@click.argument("model_name")
def download(model_name):
"""Download a model."""
with click.progressbar(length=100, label=f"Downloading {model_name}") as bar:
for _ in range(100):
bar.update(1)
if __name__ == "__main__":
cli()
Prominent features to notice: nargs=-1 accepts variable positional arguments. click.Choice() validates against a set of allowed values. click.progressbar() shows progress for long operations. Nested command groups (model list, model download) organize complex tools.
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.
Create a CLI that accepts: an output directory, a list of input files (variable arguments), a --model option with a default, and a --dry-run flag that validates everything but doesn't process. Implement validation that checks for file existence and directory writability before proceeding.