Project 13 — Argparse CLI Tool
Build a professional command-line tool with argparse subcommands, a config file, logging, and a pip-installable entry point.
What you'll learn
- 1Implement subcommands with add_subparsers
- 2Read config from ~/.toolrc (JSON or TOML)
- 3Add --verbose and --quiet logging levels
- 4Write a setup.py / pyproject.toml entry point
Usage
# Install
pip install -e .
# Usage
mytool --help
mytool init [--name NAME]
mytool run <file> [--dry-run] [--output FILE]
mytool config set <key> <value>
mytool config get <key>Config File
// ~/.toolrc
{
"output_dir": "./output",
"log_level": "INFO",
"max_workers": 4
}Common Mistakes (FAQ)
Q. How do I structure subcommands like `git commit`?
sub = parser.add_subparsers(dest='command'); then sub.add_parser('init'), sub.add_parser('run'), each with its own add_argument. Dispatch on args.command. Set required=True (Py3.7+) so running with no subcommand shows help instead of silently doing nothing.
Q. My numeric argument arrives as a string.
argparse keeps everything as str unless you say otherwise: add_argument('--workers', type=int). Same for float. Without type=, '4' + 1 raises a TypeError.
Q. How do I make a boolean flag like --dry-run?
Use action='store_true' (and 'store_false' for the inverse). The flag then takes no value: --dry-run sets args.dry_run = True, absent = False.
Q. After `pip install -e .` the `mytool` command isn't found.
Define a console_scripts entry point in pyproject.toml ([project.scripts] mytool = 'pkg.cli:main'), reinstall with pip install -e ., and reopen the shell so PATH picks up the new script.
Q. Reading ~/.toolrc fails the first time.
Expand the home dir with Path.home() / '.toolrc' (not a literal '~'), and handle the missing-file case: if it doesn't exist, fall back to defaults instead of crashing.
📝 Exercises
Try them yourself first, then open the solution to compare.
Build the CLI tool
Goal: Implement a CLI with at least 3 subcommands, config file, and entry point.
- 3+ subcommands with argparse
- Config read/write with ~/.toolrc
- --verbose/-v flag
- pip-installable entry point
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗