Chapter 1 - An Intro to Argument Parsing using argparse
Have you ever wondered how to process command line arguments in Python? Yeah, there’s a module for that. It’s called argparse, which is a replacement for optparse. In this article, we’ll be taking a whirlwind tour of this helpful module. Let’s start with something simple!
Getting Started
I have always found the simplest way to explain a coding concept is to show some code. So that’s what we’re going to do. Here’s a super simple example that doesn’t do much of anything:
>>> import argparse
>>> parser = argparse.ArgumentParser(
... description="A simple argument parser",
... epilog="This is where you might put example usage"
... )
...
>>> parser.print_help()
usage: _sandbox.py [-h]
A simple argument parser
optional arguments:
-h, --help show this help message and exit
This is where you might put example usage
Here we just import argparse and give it a description and set up a usage section. The idea here is that when you ask the program you are creating for help, it will tell you how to use it. In this case, it prints out a simple description, the default optional arguments (“-h” in this case) and example usage.
Now let’s make this example a bit more concrete. You won’t normally be parsing arguments from the command-line after all. So we’ll move the code into a Python function inside of a Python file:
1 # arg_demo.py
2
3 import argparse
4
5
6 def get_args():
7 """"""
8 parser = argparse.ArgumentParser(
9 description="A simple argument parser",
10 epilog="This is where you might put example usage"
11 )
12 return parser.parse_args()
13
14 if __name__ == '__main__':
15 get_args()
Now let’s call the script from the command line:
1 python arg_demo.py -h
This will print out the help text like we saw earlier. Now let’s learn about how to add some of our own custom arguments.
Adding Arguments
Let’s write some code that adds three new arguments that our parser can understand. We’ll add an argument that is required and two that are not. We’ll also look at adding a default and a required type. Here’s the code:
1 # arg_demo2.py
2
3 import argparse
4
5
6 def get_args():
7 """"""
8 parser = argparse.ArgumentParser(
9 description="A simple argument parser",
10 epilog="This is where you might put example usage"
11 )
12
13 # required argument
14 parser.add_argument('-x', action="store", required=True,
15 help='Help text for option X')
16 # optional arguments
17 parser.add_argument('-y', help='Help text for option Y', default=False)
18 parser.add_argument('-z', help='Help text for option Z', type=int)
19 print(parser.parse_args())
20
21 if __name__ == '__main__':
22 get_args()
Now let’s run it a few times so you can see what happens:
1 mike@pc:~/py/argsparsing$ python arg_demo2.py
2 usage: arg_demo2.py [-h] -x X [-y Y] [-z Z]
3 arg_demo2.py: error: argument -x is required
4
5 mike@pc:~/py/argsparsing$ python arg_demo2.py -x something
6 Namespace(x='something', y=False, z=None)
7
8 mike@pc:~/py/argsparsing$ python arg_demo2.py -x something -y text
9 Namespace(x='something', y='text', z=None)
10
11 mike@pc:~/py/argsparsing$ python arg_demo2.py -x something -z text
12 usage: arg_demo2.py [-h] -x X [-y Y] [-z Z]
13 arg_demo2.py: error: argument -z: invalid int value: 'text'
14
15 mike@pc:~/py/argsparsing$ python arg_demo2.py -x something -z 10
16 Namespace(x='something', y=False, z=10)
As you can see, if you run the code without passing it any arguments, you will get an error. Next we pass it just the required argument so you can see what the defaults are for the other two. Then we try passing “text” to the ‘-y’ argument and that gets stored, so we know it doesn’t require a Boolean. The last two examples show what happens when you pass an invalid and a valid value to the ‘-z’ argument.
By the way, the argument names do not have to be one character in length. You can change those something more descriptive, like ‘arg1` or ‘simulator’ or whatever you want.
Short Options and Long Options
Let’s take a look at how we might use a short option versus a long a one. We actually are already using the short option here:
1 parser.add_argument('-x', action="store", required=True,
2 help='Help text for option X')
If we wanted a long option, then we’d just need to add it right after the short one. Here’s an example:
1 parser.add_argument('-x', '--execute', action="store", required=True,
2 help='Help text for option X')
You will note that a long option is more than one character in length and that it must start with two dashes instead of one.
Options that Conflict
What do you do if you have options that conflict with each other? A common example would be running your application in verbose mode versus quiet mode. You can run it in either mode, but not both. How do we prevent the user from running it that way though? It’s actually quite easy via the mutually_exclusive_group function. Let’s pretend that options x and y cannot run at the same time and modify our code accordingly:
1 import argparse
2
3
4 def get_args():
5 """"""
6 parser = argparse.ArgumentParser(
7 description="A simple argument parser",
8 epilog="This is where you might put example usage"
9 )
10
11 group = parser.add_mutually_exclusive_group()
12 group.add_argument('-x', '--execute', action="store",
13 help='Help text for option X')
14 group.add_argument('-y', help='Help text for option Y', default=False)
15
16 parser.add_argument('-z', help='Help text for option Z', type=int)
17 print(parser.parse_args())
18
19 if __name__ == '__main__':
20 get_args()
You will note that we have to create a mutually exclusive group. Then we add the options that need to be mutually exclusive to that group. The rest go into the regular parser group. Let’s try running the code with both options like this:
1 python arg_demo3.py -x 10 -y 2
When I did this command, I ended up getting the following output:
1 usage: arg_demo3.py [-h] [-x EXECUTE | -y Y] [-z Z]
2 arg_demo2.py: error: argument -y: not allowed with argument -x/--execute
Obviously that didn’t work and the argparse module told us why.
Wrapping Up
You now know how to create the basics of an argument parser. There are many other aspects of this module that you might be interested in, such as defining an alternate destination name for the argument to be saved to, using different prefixes (i.e. ‘+’ instead of ‘-‘), creating argument groups and more. I recommend checking out the documentation for more details.