CLI Tools with argparse & Typer
Build professional command-line tools with Typer and argparse — subcommands, rich output, progress bars, and config files.
Part 1: What You Will Learn
- Parse command-line arguments with
argparse. - Create subcommands such as
addandlist. - Build a second version with Typer and automatic help.
- Design CLI commands that return useful exit behaviour and validation messages.
Part 2: Key Concepts
Command-line interfaces turn Python scripts into reusable tools. argparse is part of the standard library and has no external dependency. Typer builds on type hints to provide concise commands, validation, and automatically generated help.
Part 3: Topic-Specific Code Examples
# task_cli.py
import argparse
import json
from pathlib import Path
DATA_FILE = Path("tasks.json")
def load_tasks() -> list[str]:
if not DATA_FILE.exists():
return []
return json.loads(DATA_FILE.read_text(encoding="utf-8"))
def save_tasks(tasks: list[str]) -> None:
DATA_FILE.write_text(json.dumps(tasks, indent=2), encoding="utf-8")
def add_task(text: str) -> None:
tasks = load_tasks()
tasks.append(text)
save_tasks(tasks)
print(f"Added: {text}")
def list_tasks() -> None:
tasks = load_tasks()
if not tasks:
print("No tasks yet.")
return
for number, task in enumerate(tasks, start=1):
print(f"{number}. {task}")
def main() -> None:
parser = argparse.ArgumentParser(description="Simple task manager")
subparsers = parser.add_subparsers(dest="command", required=True)
add_parser = subparsers.add_parser("add", help="Add a task")
add_parser.add_argument("text", help="Task description")
subparsers.add_parser("list", help="List tasks")
args = parser.parse_args()
if args.command == "add":
add_task(args.text)
elif args.command == "list":
list_tasks()
if __name__ == "__main__":
main()python task_cli.py --help python task_cli.py add "Finish Python exercise" python task_cli.py list
# Install once: pip install typer
import typer
app = typer.Typer(help="Student utility CLI")
@app.command()
def greet(name: str, excited: bool = False) -> None:
message = f"Hello, {name}"
if excited:
message += "!"
typer.echo(message)
@app.command()
def grade(mark: int) -> None:
if not 0 <= mark <= 100:
raise typer.BadParameter("mark must be from 0 to 100")
typer.echo("Pass" if mark >= 50 else "Fail")
if __name__ == "__main__":
app()Part 4: How the Example Works
The argparse version creates explicit parsers and subparsers. Typer reads the function names, parameter annotations, and default values to generate commands and help. For larger tools, keep business logic in normal Python functions and let the CLI layer handle only input/output.
Part 5: Hands-On Practice
Mini project — Student Result CLI. Add commands add-result NAME MARK and grade MARK. Validate marks from 0 to 100 and add a --verbose option that displays extra processing information.
Part 6: Next Steps
Run and modify the examples in Visual Studio 2026, then continue to Lesson 21. Return to Python Tutorial Home to review the complete curriculum.