In [1]:
name = '2016-03-04-argument-parsing'
title = 'Argument parsing'
tags = 'argparse, command line'
author = 'Denis Sergeev'

In [2]:
from nb_tools import connect_notebook_to_post
from IPython.core.display import HTML

html = connect_notebook_to_post(name, title, tags, author)

Preamble

When you use a Python script in command line, you probably have some parameters or input variables set up in the beginning of the script. So you script can look like this:


In [3]:
# Parameters:
a = 1
b = '/path/to/file'
c = True

# The actual script
# ...

Every time you want to execute the program with a different set of parameters, you have to open the script in a text editor, change the necessary lines, save and run it again. Not very effective.

Another way of doing this is to pass parameters as arguments of the script. You can think of it as if your script is a standard system command, such as ls. Without arguments it displays the contents of the current directory. It also has positional and optional arguments. If you run ls on a different directory that you currently are in, you would type ls directory_name, where directory_name is a positional argument, which means that the program knows what to do with the value. If you want to display the help text of the ls command, you would type ls --help.

To give a python script the same functionality, you can use several built-in libraries.

Basic example: sys.argv

The simplest way of passing arguments to a python script can be done with sys.argv. This is just a list of strings and it contains all the values passed in, separated by whitespace. The first argument is the name of the script itself. Let's have a look.

# test.py contents
import sys

print('Arguments:', sys.argv[:])
$ python test.py 123 blabla 1-2

Arguments: ['test.py', '123', 'blabla', '1-2']

Then, the elements of sys.argv can be assigned to different parameters of your script. This method is not convenient, because the arguments are all strings, so you have to convert them to a required type. You also have to remember the order of the arguments. These two problems make this approach ineffective and prone to errors.

argparse module

Luckily, python has a module that makes working with arguments a lot more pleasant. The essential piece of code needed to start using argparse is the following:

# test2.py contents
import argparse # import the module
parser = argparse.ArgumentParser() # create parser instance
parser.parse_args() # parse arguments

This short script already has a 'help' option available (not very useful at this point):

$ python test2.py --help

usage: test2.py [-h]

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

Adding argument rules

Once you initialised the parser, you can add rules for different arguments. Note that unless you specify so, you can't pass any number of arguments, unlike in sys.argv case.

Required arguments

Let's try to add a positional (required) argument to the script and print its value.

# test2.py contents
import argparse # import the module

parser = argparse.ArgumentParser() # create parser instance
parser.add_argument('foo')
args = parser.parse_args() # parse arguments and store them in variable args

print('This is a positional argument:', args.foo)

Run the script:

$ python test2.py 123

This is a positional argument: 123

Now the script requires exactly 1 argument and raises an error if you supply it with other number of arguments.

Optional arguments

You can also make rules for your script to have optional arguments. By default, an argument is considered to be optional if its flag in parser.add_argument() function starts with dashes (usually, 1 dash for a short name and 2 dashes for long name).

For example:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', help='print optional argument')
args = parser.parse_args()
if args.verbose:
    print('The optional argument value is', args.verbose)

which gives the following output if the flag with its value is present:

$ python test.py --verbose 2
The optional argument value is 2

But it also can be run without the flag, and that does not print out anything in this case. Note that you can also customize help messages.

Next steps...

This is just a quick peek at the argparse features, and there is much more. You can specify type of arguments, number of arguments, True/False arguments, mutually exclusive arguments, file types, default values, choices and so on. There are enough capabilities to build a sophisticated and user-friendly command-line program.

Beside the documentation [1], there are several good tutorials on argparse, e.g. [2] and [3]. This post does not however intend to repeat them.

Next steps + 1

If argparse's magic is not enough for you or you want to write beautiful command line interface on a higher level, check out such packages as click [4] or climax [5].

Resources


In [4]:
HTML(html)


Out[4]:

This post was written as an IPython (Jupyter) notebook. You can view or download it using nbviewer.