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:
- developers use CLI tools daily (git, pip, docker)
- servers run scripts using CLI arguments
- automations depend on commands and flags
- real engineers build internal CLI tools to improve workflows
- cloud deployment (AWS/GCP/Azure) relies heavily on CLI automation
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:
- Default settings
- Config file (YAML/JSON/TOML)
- Environment variables
- Command-line arguments (highest priority)
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:
- ✔ Use environment variables: export API_KEY="123"
- ✔ Never store secrets in code
- ✔ Use a .env loader (python-dotenv)
- ✔ Hide passwords in Typer prompts
🧪 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.
- ✔ ThreadPoolExecutor (I/O tasks)
- ✔ ProcessPoolExecutor (CPU tasks)
- ✔ asyncio (many lightweight tasks)
- ✔ caching (functools.lru_cache)
- ✔ chunk streaming
🚀 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
- ✔ PyPI (pip install)
- ✔ Homebrew (Mac)
- ✔ Winget (Windows)
- ✔ Snap/Apt (Linux)
- ✔ GitHub Releases (binaries)
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
- Previous: DevOps Automation
- Next: Final Project