Chapter 8
Programs That Take Arguments
A Program's Interface Is a Contract
Chapter 7 ended with a real converter, but only for the two filenames written inside main(). A person cannot choose another input or output without editing the program. This chapter turns that fixed run into a
The shell itself is not the subject again. You already know how to stand in a project root and run a Python file. The new work is deciding what the program accepts and what every possible run promises in return.
Write the command before the parser
This is the complete interface we will build:
python catalog.py INPUT_PATH OUTPUT_PATH [--minimum-quantity COUNT]
INPUT_PATH and OUTPUT_PATH are required positional
--minimum-quantity is an option. Its name makes the 0. A count must be a whole number of zero or more. The program keeps items whose quantity is at least that count, without reordering or deduplicating them.
-h and --help display the interface without running a conversion.
Two streams and three statuses
A command-line program has two text streams. Ordinary results go to stdout. Actionable errors go to stderr. Keeping them separate lets another tool save the successful result without mixing failure text into it.
The program also finishes with an exit status:
| Situation | stdout | stderr | Status |
|---|---|---|---|
| Conversion succeeds | Wrote N items to PATH. | empty | 0 |
| Input or catalog data is invalid | empty | Could not convert catalog: ... | 1 |
| Arguments are missing, unknown, or invalid | empty | usage plus parser error | 2 |
| Help requested | help text | empty | 0 |
The output artifact is equally exact. A successful run writes validated UTF-8 JSON to the requested output path. An argument error never starts conversion. An unexpected programming error still gets a
In the command python catalog.py source.csv result.json, how does the program know which path is the input?
Why does an expected malformed-catalog message belong on stderr?
Next, argparse will turn the first two pieces of that written contract into values without making the converter rediscover CSV or JSON.
Before writing any parser code, try describing your interface to Monty in one sentence and asking what a user would find surprising about it. Interfaces are much cheaper to change now than after they exist.