Commandline Parsing with argparse

Basics

  • Commandline parsing using only raw sys.argv is tedious (see here)

  • Nobody wants positional arguments

  • Error checking is rarely done correctly ⟶ IndexError when accessing an argument the user didn’t pass

The following program would be called like so …

$ python raw.py 0.5 samples.csv
import sys

interval = float(sys.argv[1])
outputfilename = sys.argv[2]

# ...

If the user didn’t give the filename argument, position 2 would be invalid in sys.argv

$ python raw.py 0.5
Traceback (most recent call last):
  File "/home/jfasch/work/jfasch-home/trainings/material/soup/python/drafts/argparse/raw.py", line 4, in <module>
    outputfilename = sys.argv[2]
IndexError: list index out of range

Handling Positional Arguments

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('interval', type=float, help='interval (in seconds) that we retrieve samples')
parser.add_argument('outputfilename', help='file to write samples to ("-" for stdout)')

args = parser.parse_args()

interval = args.interval
outputfilename = args.outputfilename

# ...

Omitting the second (filename) argument leads to an error, clearly, but that comes with a usage message,

$ python positional.py 0.5
usage: positional.py [-h] interval outputfilename
positional.py: error: the following arguments are required: outputfilename

The user will then say what she is suggested,

$ python positional.py -h
usage: positional.py [-h] interval outputfilename

positional arguments:
  interval        interval (in seconds) that we retrieve samples
  outputfilename  file to write samples to ("-" for stdout)

optional arguments:
  -h, --help      show this help message and exit

Ah:

$ python positional.py 0.5 samples.csv
...

The type parameter to add_argument() helps, too,

$ python positional.py 0,5 samples.csv
usage: positional.py [-h] interval outputfilename
positional.py: error: argument interval: invalid float value: '0,5'

Handling Named Arguments: --interval

Most people prefer named arguments over positional arguments, for readability …

$ python named.py --interval 0.5 --outputfilename samples.csv
...

This is as simple as …

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-i', '--interval', type=float, help='interval (in seconds) that we retrieve samples')
parser.add_argument('-o', '--outputfilename', help='file to write samples to ("-" for stdout)')

args = parser.parse_args()

interval = args.interval
outputfilename = args.outputfilename

# ...

The command can then be invoked in many ways …

Full long options (best to use in shell scripts, for readability)
$ python named.py --interval 0.5 --outputfilename samples.csv
Short (single character) options
$ python named.py -i 0.5 -o samples.csv
Giving unique prefixes is sufficient with long options
$ python named.py --int 0.5 --ou samples.csv