Creating command-line programs with Python’s argparse module

A few years ago we wrote a series of posts on how to write a Python module called fitness.py. Along the way, we learned about writing Python functions to avoid repeating ourselves (1), packaging these functions into a useful Python module that we can reuse (2), and finally we learned about the odd looking if __name__ == "__main__", which allowed us to run our module from the command-line (3).

However, there are times when we want to have additional control over how our program runs from the command line. We may want to provide one or more inputs, some of which may be optional, or we may want to toggle some functionality on or off; for example, reporting results in centimeters or inches. For cases like these, we will want to use a tool specifically designed to deal with retrieving inputs and variables from the command line: the Python argparse module.

argparse module

The argparse module is designed to facilitate the parsing of command line arguments. In a more traditional sense, ‘parse’ means to separate a sentence into grammatical parts, such as subject, verb, etc. In the context of computer code in general, and the command-line in particular, to parse a command-line command means to separate it into its parts.

The best way to see how argparse works is to see it in action.

Let’s create a simple command line tool called ‘argparse_example.py’ that takes as input height and weight, and outputs the computed BMI.

from argparse import ArgumentParser


def main(args):
    bmi = bmi_calc(args.weight, args.height)
    print(f'BMI = {bmi}')


def bmi_calc(weight_kg, height_m):
    """Calculate BMI from weight in kg and height in meters"""
    bmi = int(weight_kg / height_m ** 2)
    return bmi

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument(
        "weight",
        type=float,
        default=None,
        help="Person's weight in Kg",
    )
    parser.add_argument(
        "height",
        type=float,
        default=None,
        help="Person's height in metres",
    )
    args = parser.parse_args()
    main(args)

First, we import ArgumentParser from argparse.

Next, skip down to the if __name__ == "__main__" part of the code. If you recall from a previous post (3), this tells Python that you are running this module as a program; the code below the if statement will only be run if you run the program. The code below this if statement won’t run if we import this module in another module (i.e. import argparse_example).

Here we create a parse object using this line: parser = ArgumentParser(). Next, we add two arguments, height and weight, using the parse.add_argument() method.

Finally, we formally parse the arguments by calling parser.parse_args() and assigning the output to a variable called args. This variable contains the parsed arguments, which we can now use to calculate the BMI.

To do this, we pass args to our main() function, which is defined at the very top of our module. At present, the content of main() is quite simple (and could have been bypassed), but this serves as an entry point for our program.

With this in place, we can now call our program from the command line as follows:

$ python argparse_example.py 75 1.8
BMI = 23
$ python argparse_example.py 62 1.2
BMI = 43
$ python argparse_example.py -h
usage: argparse_example.py [-h] weight height

positional arguments:
  weight      Person's weight in Kg
  height      Person's height in metres

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

Great, we now understand the basics of how to use argparse. You can do a lot more with argparse, a few of which we will cover next as we update our fitness.py module (3) to use argparse.

fitness_argparse.py

The original fitness.py program has been updated to use the argparse module, and can be found here.

First, let’s see the help that is automatically generated by argparse when we call our program with the -h or --help optional argument.

$ python fitness_argparse.py -h
usage: fitness_argparse.py [-h] [-i INITIALS] [-a AGE] [-s SYSTOLIC] [-d DIASTOLIC] [-g]
                           weight height

fitness_argparse v0.1 

Created by Martin Héroux (heroux.martin at gmail.com) 

Determines fitness level based on a few simple inputs. 

USAGE: $ python fitness_argparse.py --initials MH --weight 70 --height 1.75 --age 40 --systolic 135 --diastolic 82

positional arguments:
  weight                Person's weight in Kg
  height                Person's height in metres

optional arguments:
  -h, --help            show this help message and exit
  -i INITIALS, --initials INITIALS
                        Initials of person
  -a AGE, --age AGE     Person's age
  -s SYSTOLIC, --systolic SYSTOLIC
                        Person's systolic blood pressure
  -d DIASTOLIC, --diastolic DIASTOLIC
                        Person's diastolic blood pressure
  -g, --greeting        Provide a brief greeting to user


Next, we can call our program with and without some of the optional arguments.

$ python fitness_argparse.py 80 1.9

        weight = 80.0 kg
        height = 1.9 m
        bmi = 22.0

$ python fitness_argparse.py 80 1.9 --age 35
        
        weight = 80.0 kg
        height = 1.9 m
        bmi = 22.0
        age = 35 years old
        predicted maximal heart rate = 183.5 bpm

$ python fitness_argparse.py 80 1.9 --initials MH --age 35 --systolic 140 --diastolic 68

        
MH
        weight = 80.0 kg
        height = 1.9 m
        bmi = 22.0
        age = 35 years old
        predicted maximal heart rate = 183.5 bpm
        blood pressure = 140/68
        blood presure = stage 2 hypertension
 

Thus far, we have used positional and optional arguments, and these have been assigned to str, int or float variables types. However, argparse gives us access to lots more functionality. As a simple example, fitness_argparse.py includes a different type of argument:

 parser.add_argument(
        "-g",
        "--greeting",
        action="store_true",
        help="Provide a brief greeting to user",
    )

The code snippet above shows that we have added an optional argument called greeting, that we can call on the command line by including either -g or --greeting. We can see that this argument has an action variable that is set to "store_true"; this means that if we include this optional argument flag (no actual argument needed), we can toggle greeting to True. When we don’t include this optional argument flag, greeting defaults to False.

Here is a simple example calling fitness_argparse.py with and without this optional argument.

$ python fitness_argparse.py 80 1.9
        
        weight = 80.0 kg
        height = 1.9 m
        bmi = 22.0

$ python fitness_argparse.py 80 1.9 -g

Great job! Thinking of your fitness is a great thing to do for yourself.
        
        weight = 80.0 kg
        height = 1.9 m
        bmi = 22.0


Summary

We don’t always need to turn our Python programs into command line tools. However, it can come in very handy at times, and knowing about argparse will prove invaluable in these instances.

The present post is a brief introduction of key aspects of the argparse module. For those that are curious what else argparse can do, the folks over at RealPython have prepared a readable, but detailed tutorial . For those that like getting their information from the sources, you can also check out the official documentation (6).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s