Handling arguments like an adult
Recipe Difficulty: Easy
Python Version: 2.7 or 3.5
Operating System: Any
Person A: I came here for a good argument! Person B: Ah, no you didn't, you came here for an argument! Person A: An argument isn't just contradiction. Person B: Well! it can be! Person A: No it can't! An argument is a connected series of statements intended to establish a proposition. Person B: No it isn't! Person A: Yes it is! It isn't just contradiction.
Monty Python (http://www.montypython.net/scripts/argument.php) aside, arguments are an integral part of any script. Arguments allow us to provide an interface for users to specify options and configurations that change the way the code behaves. Effective use of arguments, not just contradictions, can make a tool more versatile and a favorite among examiners.
Getting started
All libraries used in this script are present in Python's standard library. While there are other argument-handling libraries available, such as optparse
and ConfigParser
, our scripts will leverage argparse
as our de facto command-line handler. While optparse
was the library to use in prior versions of Python, argparse
has served as the replacement for creating argument handling code. The ConfigParser
library parses arguments from a configuration file instead of the command line. This is useful for code that requires a large number of arguments or has a significant number of options. We will not cover ConfigParser
in this book, though it is worth exploring if you find your argparse
configuration becomes difficult to maintain.
Note
To learn more about the argparse
library, visit https://docs.python.org/3/library/argparse.html.
How to do it…
In this script, we perform the following steps:
- Create positional and optional arguments.
- Add descriptions to arguments.
- Configure arguments with select choices.
How it works…
To begin, we import print_function
and the argparse
module. By importing the print_function
from the __future__
library we can write print statements as they are written in Python 3.X but still run them in Python 2.X. This allows us to make recipes compatible with both Python 2.X and 3.X. Where possible, we carry this through with most recipes in the book.
After creating a few descriptive variables about the recipe, we initialize our ArgumentParser
instance. Within the constructor, we define the description
and epilog
keyword arguments. This data will display when the user specifies the -h
argument and can give the user additional context about the script being run. The argparse
library is very flexible and can scale in complexity if required for a script. Throughout this book, we cover many of the library's different features, which are detailed on its document page:
from __future__ import print_function import argparse __authors__ = ["Chapin Bryce", "Preston Miller"] __date__ = 20170815 __description__ = 'A simple argparse example' parser = argparse.ArgumentParser( description=__description__, epilog="Developed by {} on {}".format( ", ".join(__authors__), __date__) )
With the parser instance created, we can now begin adding arguments to our command-line handler. There are two types of arguments: positional and optional. Positional arguments start with an alphabetic character, unlike optional arguments, which start with a dash, and are required to execute the script. Optional arguments start with a single or double dash character and are non-positional (that is, the order does not matter). These characteristics can be manually specified to overwrite the default behavior we’ve described if desired. The following code block illustrates how to create two positional arguments:
# Add Positional Arguments parser.add_argument("INPUT_FILE", help="Path to input file") parser.add_argument("OUTPUT_FILE", help="Path to output file")
In addition to changing whether an argument is required, we can specify help information, create default values, and other actions. The help
parameter is useful in conveying what the user should provide. Other important parameters are default
, type
, choices
, and action
. The default
parameter allows us to set a default value, while type
converts the type of the input, which is a string by default, to the specified Python object type. The choices
parameter uses a defined list, dictionary, or set to create valid options the user can select from.
The action
parameter specifies the type of action that should be applied to a given argument. Some common actions include store
, which is the default and stores the passed value associated with the argument; store_true
, which assigns True
to the argument; and version
, which prints the version of the code specified by the version parameter:
# Optional Arguments parser.add_argument("--hash", help="Hash the files", action="store_true") parser.add_argument("--hash-algorithm", help="Hash algorithm to use. ie md5, sha1, sha256", choices=['md5', 'sha1', 'sha256'], default="sha256" ) parser.add_argument("-v", "--version", "--script-version", help="Displays script version information", action="version", version=str(__date__) ) parser.add_argument('-l', '--log', help="Path to log file", required=True)
With our arguments defined and configured, we can now parse them and use the provided inputs in our code. The following snippet shows how we can access the values and test whether the user specified an optional argument. Notice how we refer to arguments by the name we assign them. If we specify a short and long argument name, we must use the long name:
# Parsing and using the arguments args = parser.parse_args() input_file = args.INPUT_FILE output_file = args.OUTPUT_FILE if args.hash: ha = args.hash_algorithm print("File hashing enabled with {} algorithm".format(ha)) if not args.log: print("Log file not defined. Will write to stdout")
When combined into a script and executed at the command line with the -h
argument, the preceding code will provide the following output:

As seen here, the -h
flag displays the script help information, automatically created by argparse
, along with the valid options for the --hash-algorithm
argument. We can also use the -v
option to display the version information. The --script-version
argument displays the version in the same manner as the -v
or -version
arguments as shown here:

The following screenshot shows the message printed to the console when we select one of our valid hashing algorithms:

There's more…
This script can be further improved. We have provided a couple of recommendations here:
- Explore additional
argparse
functionality. For example, theargparse.FileType
object can be used to accept aFile
object as an input. - We can also use the
argparse.ArgumentDefaultsHelpFormatter
class to show defaults we set to the user. This is helpful when combined with optional arguments to show the user what will be used if nothing is specified.