Objective
Learn to use the argparse module to easily parse python scripts parameters
Requirements
- Basic knowledge of python and object oriented concepts
Difficulty
EASY
Conventions
- # – requires given linux commands to be executed with root privileges either
directly as a root user or by use ofsudo
command - $ – requires given linux commands to be executed as a regular non-privileged user
Introduction
In a previous article we have seen how to parse command line arguments using getopts in the context of bash scripts (you can find the article here). Now we will see how to accomplish the same task, in a more powerful way, when writing a python script.
Initialize the parser
To achieve our goal, we are going to use a python module called argparse
. It will let us specify our command line parameters, and will automatically generate the script help message based on them. So let’s begin, we will call our script “printerscript.py”:
#!/usr/bin/env python
import argparse
if __name__ == '__main__':
# Initialize the parser
parser = argparse.ArgumentParser(
description="simple script to demonstrate argparse usage"
)
The first thing to do is, obviously, to import the argparse
module. After that we proceed to initialize the parser. The description
keyword, passed to the parser constructor is optional, but allows us to add a brief description of the script when the help message is displayed.
There are other keywords we can use to further customize the behavior of the parser: for example providing the epilog
keyword we can provide a text to be displayed after the main help message, or by using prog
we can specify the name of the program to be displayed in the same context (by default sys.argv[0] is used).
Adding a positional parameter
Now it’s time to add our first positional parameter to the script. In this case we will add the parameter “printme”, that is the string that will be printed by our test script. We accomplish this by using the add_argument()
method of the parser object we initialized above:
parser.add_argument('printme', help="The string to be printed")
The first argument we provided to the method is the name of the parameter, and the second one, optional, is help
. Using this keyword, we can specify the description for the parameter that will be displayed in the help message generated by argparse.
It’s important to notice that by default the parameters will be considered as strings: to specify another data type, we must use the type
keyword. For example, if we wanted our argument to be converted to an integer, we would have specified it this way:
parser.add_argument('printme', type=int)
Once we added our parameter, we must invoke the parse_args()
method of the parser object. This method will return an instance of the argparse.Namespace
class: the parsed parameters will be stored as attributes of this instance. Finally we can add a line to print the variable. At this point the script should look this way:
#!/usr/bin/env python
import argparse
if __name__ == '__main__':
# Initialize the parser
parser = argparse.ArgumentParser(
description="simple script to demonstrate argparse usage"
)
# Add the positional parameter
parser.add_argument('printme', help="The string to be printed")
# Parse the arguments
arguments = parser.parse_args()
# Finally print the passed string
print(arguments.printme)
Let’s execute it:
$ ./printerscript.py "hello world!" hello world!
The string we passed has been printed has expected. But what if we didn’t provide it? The help message would have been showed, describing the script correct usage:
$ ./printerscript.py usage: printerscript.py [-h] printme printerscript.py: error: too few arguments
Adding an optional parameter
Optional parameters are not mandatory for the usage of the script, but they are used to modify its behavior. Argparse recognizes them when it sees that hyphens are provided in the description, so for example:
parser.add_argument(
'-r', '--repeat',
help="number of times to print the string",
type=int,
default=1
)
The name of the parameter is prefixed with hyphens (we can specify both the short and the long parameter version). In this case we added the optional parameter --repeat
which specifies how many times the string must be printed. We also used the default
keyword. This is really important, because through it, we can specify the value the attribute will assume if the parameter it’s not explicitly provided when calling the script.
At this point, to verify that the parameter works as expected, all we have to do is modify our script in order to repeat the printing of the string for the specified number of times, therefore we enclose the print()
function into a little for loop
:
for i in range(0, arguments.repeat):
print(arguments.printme)
Let’s try it:
$ ./printerscript.py --repeat=3 "hello world!" hello world! hello world! hello world!
All went as expected. In addition, the help message has also been updated, and now includes a description of the new optional parameter:
./printerscript.py --help usage: printerscript.py [-h] [-r REPEAT] printme simple script to demonstrate argparse usage positional arguments: printme The string to be printed optional arguments: -h, --help show this help message and exit -r REPEAT, --repeat REPEAT number of times to print the string
As said above, when argparse
sees that a parameter is prefixed with hyphens, it assumes that it is optional. To modify this behavior and “declare” it as mandatory, we can use the required
keyword when adding the parameter, in the form: required=True
.
The “dest” keyword
Normally the value provided for a parameter will be stored as an attribute named after the first argument given to the add_argument()
method in the case of positional parameters, or the first long string option (with the hyphens removed: the –repeat string will become the ‘repeat’ attribute) in the case of optional parameters. In the latter case, if a long string option is not available, the short one is used. The dest
keyword allows us to specify a custom attribute name instead of relying on this behavior.
The “action” keyword
When using the add_argument()
method we can specify the behavior to use for the parsed options by using another keyword: action
. The default action is to assign the passed value to the corresponding attribute. In the case of our tiny script, for example, the value provided for the --repeat
parameter, will be assigned to the ‘repeat’ attribute of the argparse.Namespace
class once the arguments are parsed. This behavior, however, can also be modified. Let’s describe the other main options in brief:
store_true and store_false
By specifying this action, we are basically saying that the parameter doesn’t require an argument: True
will be assigned as the value to the corresponding attribute if the option is provided, or False
otherwise. store_true
and store_false
will provide respectively a default value of True
and False
.
store_const
This is similar to the option above, but by using it as a value for the action
keyword, instead of a Boolean, a constant
value will be assigned to the attribute if the parameter is used. This value is specified itself by using the const
keyword:
parser.add_argument("--random-option", action="store_const", const=yourvalue)
append
If append
is used as value of the action
keyword, a list will be created and referenced by the corresponding parameter attribute: the provided value will be appended to it. This is useful in case the parameter is provided more than once:
parser.add_argument('--random-option', action="append")
append_const
Just like when using append
, a value will appended to the list referenced by the parameter attribute. The difference is that in this case, the value is not provided by the user, but declared when adding the parameter, again, via the const
keyword:
parser.add_argument(
'--randomoption',
action="append_const",
const="the value to append"
)
Mutually exclusive optional parameters
In certain situation we may need to make some options mutually exclusive. The argparse
module lets us accomplish this task in a vary easy way. Basically what we are going to do is to create a separate group of options using the add_mutually_exclusive_group()
method of the parser object, and add our arguments to it. For example:
parser = argparse.ArgumentParser();
# create our group of mutually exclusive arguments
mutually_exclusive = parser.add_mutually_exclusive_group()
mutually_exclusive.add_argument("--foo", help="foo excludes bar")
mutually_exclusive.add_argument("--bar", help="bar excludes foo")
One thing to notice is that to be part of a mutually_exclusive_group
arguments must be optional, therefore positional arguments, or arguments you defined as required (required=True
) are not allowed in it.
At this point you should have an idea of how argparse
works. However, we only scratched the surface of what this module has to offer: for a complete description of all its functionalities please go ahead and read the documentation, you won’t regret it. Nice scripting!