RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Fredoline Eruo
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /Python for AI — Zero to Useful
  6. /Ch. 32
Python for AI — Zero to Useful

32. CLI Argument Parsing

Chapter 32 of 36 · 15 min
KEY INSIGHT

Use `click.Path(exists=True)` for file validation—the CLI won't proceed if the path doesn't exist. For custom validation, raise `click.Abort()` or use `click.BadParameter()`. Separate validation from business logic.

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.

EXERCISE

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.

← Chapter 31
Building a CLI Tool
Chapter 33 →
CLI with Rich Output