Cli Tools

Build real command-line tools the same way professionals build developer utilities, automated scripts, data pipelines, AI model runners, and deployment tools. Master both argparse (standard, built-in) and Typer (modern, FastAPI-style) for creating production-grade CLI applications.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

🧰 What You'll Learn

This lesson teaches how to build real command-line tools, the same way professionals build:

1. argparse (standard, low-level, built into Python) — Perfect for: small scripts, simple tools, full control.

2. Typer (modern, high-level, super-fast development) — Perfect for: professional apps, developer tools, banners, sub-commands, autocomplete.

Part 1: CLI Fundamentals — argparse Basics & Introduction to Typer

🔥 1. Why Command-Line Tools Matter

Before GUIs, everything ran in the terminal. But even today:

CLI Tool

What It Does

Why It's Fast

git push

Upload code to server

1 command vs. clicking through UI

pip install

Add a library

Instant, no browser needed

docker run

Start a container

Scriptable, automatable

python script.py --help

Show tool options

Self-documenting

Having CLI-building skills makes you 10× more valuable as a developer.

⚙️ 2. argparse Basics — The Standard Python CLI Option

argparse ships with Python. No installation needed.

🧠 3. Positional vs Optional Arguments

Type

Syntax

Example

Required?

Positional

filename

python tool.py data.csv

Yes

Optional

--verbose or -v

python tool.py --verbose

No

Optional flags improve usability and mirror real CLI tools like pip, git, and docker.

📝 4. Typed Arguments: int, float, file paths

🧩 5. Sub-Commands (Like Git)

Many tools behave like: git add, git push, git commit. You can create the same pattern:

This transforms your script into a multi-command CLI application.

⚡ 6. Real Project Example — File Organizer

🚀 7. Introduction to Typer (The Modern CLI Framework)

Typer is built by the creator of FastAPI. It offers:

Feature

argparse

Typer

Setup Code

10+ lines

2-3 lines

Type Validation

Manual

Automatic

Help Generation

Basic

Beautiful

Colors/Formatting

Built-in

Autocompletion

Complex

One command

🧠 8. Basic Typer Example

🎛 9. Optional Arguments in Typer

Usage: python tool.py download https://example.com --retries 5 --verbose

🧩 10. Typed Options & Defaults

This makes code cleaner and more maintainable.

🏗 11. Subcommands (Typer's strongest feature)

You now have a full CLI program with modules.

🧠 12. Real Project Example — AI Assistant CLI

Part 2: Advanced Patterns — Real Engineering Features

In this part, we go deeper into real engineering patterns, advanced argument features, error handling, output design, color/UI improvements, and structuring multi-file CLI apps the same way professionals build tools like pip, docker, aws-cli, git, uv, and fastapi-cli.

⚡ 1. Advanced argparse Features You MUST Know

Sometimes a user should only choose one option:

Now the user cannot do: python tool.py --verbose --quiet

This is used for logging mode, compression types, environment switches, etc.

Stops invalid inputs before they crash your program.

🧠 2. Using Config Files + CLI Arguments Together

Professional CLI tools combine: environment variables, config files, command-line arguments.

Example: python deploy.py --config config.yaml --env production

argparse supports this pattern through: FileType, custom loaders, layered parsing logic

🧰 3. Advanced Typer Patterns (Modern CLI Engineering)

⚙️ 4. Handling Errors Gracefully

🧩 5. Building Multi-Command Apps (Professional Structure)

Real CLIs use folder architectures. For Typer:

🧠 6. Environment-Aware Commands

📦 7. Creating "Plugins" for CLI Tools

🔍 8. Auto-generated Help Screens

This UI alone saves hours of documentation. argparse also generates help automatically, but Typer's formatting is noticeably cleaner.

🧱 9. Testing CLI Tools

You can test argparse & Typer apps with pytest using CliRunner. Example for Typer:

🌐 10. Packaging Your CLI as a PIP Installable Tool

You can turn a Typer/argparse script into a real installable command:

Part 3: Enterprise-Grade CLI Engineering — Production Deployment

This final section focuses on enterprise-grade CLI engineering, including structured logging, configuration layers, packaging/distribution, versioning, interactive shell modes, autocomplete, performance optimisation, security best practices, and production deployment patterns.

⚡ 1. Enterprise-Style Configuration Layers

Professional CLI apps often support configuration from multiple layers:

This allows flexible behaviour: users can override defaults, automation pipelines can use environment variables, developers can test using temporary config files. Typer-based tools commonly use pydantic or dynaconf to manage all layers cleanly.

🧠 2. CLI Autocompletion (Bash, Zsh, Fish)

Modern CLI tools include autocomplete for: commands, options, file paths, arguments.

Under the hood, it generates shell-compatible scripts. This dramatically improves user experience and is a key part of professional developer tools.

📦 3. Packaging as a Standalone Executable (Windows, Mac, Linux)

Not every user has Python installed. You can turn your CLI into one executable file using:

Briefcase — Creates full OS-native installers.

This is how tools become "real" apps that run anywhere.

🧩 4. Versioning & Release Flows

⚙️ 5. Creating Subcommands Like Professional Tools (docker, git, aws-cli)

Large CLI tools organise commands into modules:

🧵 6. Integrating Your CLI With Other Tools (Pipes & Redirects)

CLI tools should work with Linux/Windows pipes:

🔒 7. Authentication & Secrets Management

If your CLI interacts with APIs, databases, or cloud services, it must handle secrets safely. Best practices:

🧪 8. Writing Realistic Tests for CLI Behaviour

🌐 9. Color, Formatting & Tabular Output (Rich + Typer)

Real-world tools display: tables, panels, logs, status values, colour-coded results.

🧱 10. Performance & Concurrency Inside CLI Tools

CLI commands often do: API requests, file scanning, JSON parsing, image processing, database queries.

🚀 11. Real Engineering Pattern — Modular "Actions" Layer

For large CLIs, never put logic inside the command functions. Instead:

This allows: rewiring logic, sharing helpers, unit testing functions directly, keeping CLI layer clean. This is how professional tools stay maintainable.

📦 12. Distribution: PyPI, Brew, Winget, and GitHub Releases

This is the path for turning your CLI into a global developer tool.

🎉 Final Summary

After completing all 3 parts, you can build CLI tools with:

You now have the skills to build production-grade CLI tools!

📋 Quick Reference — CLI Tools

Syntax / Tool

What it does

argparse.ArgumentParser()

Parse CLI arguments (stdlib)

parser.add_argument('--name')

Add a named flag argument

@app.command() (Typer)

Define a Typer CLI command

typer.Option(..., help=)

Add option with help text

rich.print("[bold]text[/bold]")

Pretty terminal output

You can now build polished CLI tools with argument parsing, progress bars, coloured output, and bash completions.

Up next: Virtual Environments — manage isolated Python environments for every project.

Practice quiz

Which CLI library ships with Python and needs no installation?

  • Typer
  • Click
  • argparse
  • Rich

Answer: argparse. argparse is part of the standard library, so it is built into Python with no extra install.

In argparse, what is the difference between a positional and an optional argument?

  • Positionals are required by name; optionals start with - or -- and are not required
  • Positionals start with --, optionals do not
  • They are identical
  • Optionals must come first

Answer: Positionals are required by name; optionals start with - or -- and are not required. Positional arguments (like a filename) are required; optional flags such as --verbose start with - or -- and are not required.

How do you make an argparse flag like --verbose a simple on/off switch?

  • type=bool
  • nargs=0

action='store_true' makes the flag store True when present and False otherwise.

Which add_argument option restricts a value to a fixed set like low/medium/high?

  • nargs
  • choices
  • default
  • metavar

Answer: choices. choices=['low','medium','high'] makes argparse reject any value outside that list automatically.

What does nargs="+" do for an argument?

  • Accepts one or more values into a list
  • Makes it optional
  • Adds a default of 1
  • Allows only one value

Answer: Accepts one or more values into a list. nargs='+' collects one or more values, useful for batch operations like --files a.txt b.txt c.txt.

How does argparse let a tool behave like git with add/commit/push subcommands?

  • parser.add_argument('sub')
  • parser.subcommand()
  • parser.add_subparsers() with sub.add_parser('add')
  • It cannot do subcommands

Answer: parser.add_subparsers() with sub.add_parser('add'). add_subparsers() creates a subcommand dispatcher, and sub.add_parser('add') defines each subcommand.

Who created Typer, and what framework is it modeled after?

  • Guido van Rossum, modeled on Django
  • The creator of FastAPI, sharing its type-hint style
  • The Flask team
  • The pytest team

Answer: The creator of FastAPI, sharing its type-hint style. Typer is built by the creator of FastAPI and uses the same type-hint-driven, modern style.

How does Typer know an argument's type and validate it?

  • You write manual isinstance checks
  • It guesses from the value
  • You pass a type= argument like argparse
  • From the function's type hints (e.g. name: str, count: int)

Answer: From the function's type hints (e.g. name: str, count: int). Typer reads the command function's type hints to validate and convert arguments automatically.

Which is the recommended way to keep secrets like API keys out of a CLI tool?

  • Hard-code them in the script
  • Read them from environment variables (e.g. os.getenv)
  • Store them in the --help text
  • Commit them to Git

Answer: Read them from environment variables (e.g. os.getenv). The lesson stresses using environment variables / .env loaders and never hard-coding secrets in code.

In pyproject.toml, what makes a Typer/argparse script installable as a real command?

A [project.scripts] entry like learnfast = 'app.main:app' exposes the app as an installable console command.

Continue this course