2026-10-16 — Python CLI tested with pytest¶
Resource watched¶
Title: Python cli tested with pytest
Type: Video
Summary and takeaways¶
Here are the key points for developing Command Line Interface tool with Python:
-
The machanism of
if __name__ == 'name'is the key step to separate executable and importable parts in the .py module. -
Write
def main()and call it from underif __name__ == 'name' -
To parse arguments,
sys.argvis the most basic mechanism, but it's so basic that it requires a lot of code around it to validate and control it.argparseis a much better built-in solution with a lot of utilities. -
Passing argument namespace to main
main(argv)makes it more testable. -
Another good practice is to exit with a return code. This can become particularly relevant if your tool has many executions cenarios and failure modes.
-
intreturn code can be programmed manually or you can useargparseerror message built-ins. -
Return codes have to be produced with
sys.exitorraise SystemExit(...) -
Another option is to return
intfrommainand doexit(main()). However this approach will depend onsiteand that has some edge cases. -
Helpful for working in
bash: commandecho $?will display the exit code of the previous task. -
Add type annotations for your CLI!
-
What about testing?
-
Test with
pytest.raises(SystemExit, ...) - If you want to test for stdout/err output you can use
capsysfixture in the pytest. - Check both stdout and sterr (e.g. we can expect that stderr is empty)
- Check the exit code.
-
Look for examples on CLI testing in other packages.
-
When you prompt GenAI for CLI or tests for CLI you have to understand what you are asking for, otherwise your output can be dramatically overengineered.
Minimal example:
import sys
import argparse
def main(argv: Optional[Sequence[str]] = None) -> int:
parser = argparse.ArgumentParser()
parser.add_argument()
args = parser.parse_args(argv)
if args.person == '':
print('Person argument cannot be empty?', file=sys.stderr)
return 1
print(f"Hello, {args.person}!")
return 0
if __name__ == 'name'
exit(main())
Resources¶
-
argparsedocumentation. It has many capabilities. Particularly valuable sections: -
Adding arguments with
add_argumenthas plenty of useful tools. E.g. you can specify types of the arguments and validation of the type throughactionparameter. -
python docs on
SystemExit -
An example of CLI testing can be found in the
cookiecutterproject. For example, here is a link totests_cli.py -
An example of integration tests with
martinize