I know many of you are just looking for some reference code to copy so I put that here at the top, but if you want to learn more, a detailed explanation can be found in the video above and in the text below.
import argparse
def parse_args():
parser = argparse.ArgumentParser(
description="This gives examples of how to use argparse."
)
# Positional argument
parser.add_argument(
"echo",
help="Echo the string you use here"
)
# Optional argument
parser.add_argument(
"--name",
help="Give me a name.",
action="store"
)
# Action store_true: Useful for when you want a yes or a no
parser.add_argument(
"--switch_on",
help="To turn the switch on.",
action="store_true"
)
# Getting other types of input by conversion
parser.add_argument(
"--count",
help="Give me a number.",
type=int
)
# Making it required
parser.add_argument(
"--last_name",
help="Your last name.",
required=True
)
# Multiple inputs with nargs="*"
parser.add_argument(
"--add",
help="Add the following numbers.",
type=int,
nargs="*"
)
# Multiple input with nargs="+"
parser.add_argument(
"--numbers",
help="Give me at least one number.",
type=int,
nargs="+"
)
### BONUS CONTENT ###
# Key Value pairs as input
parser.add_argument(
"--pairs",
metavar="KEY=VALUE",
nargs='*',
help="Create a set of key-value pairs."
)
return parser.parse_args()
def main():
args = parse_args()
# The rest of the program is here
print("echo: {}".format(args.echo))
if args.name:
print("name: {}".format(args.name))
print("action store_true: {}".format(args.switch_on))
if args.count:
print("count: {}".format(args.count))
print("type(count): {}".format(type(args.count)))
print("last_name: {}".format(args.last_name))
if args.add:
print("add: {}".format(args.add))
print("sum(add) = {}".format(sum(args.add)))
print("numbers: {}".format(args.numbers))
if args.pairs:
print("pairs: {}".format(args.pairs))
print("parsed pairs: {}".format(parse_pairs(args.pairs)))
def parse_pairs(pairs):
d = {}
for pair in pairs:
items = pair.split("=")
d[items[0]] = items[1]
return d
if __name__ == '__main__':
main()
Environment Setup
I use Python virtual environments for my PyQt development. If you have never worked with one, see my article covering the basics here. For this project I just pip install
ed argparse.
Boilerplate Code
I am going to go over each line of code from the program above but first I am going to go over the structure of the program and the boilerplate code (i.e. the common code you will see in a lot of programs). At the top of the file we import argparse
:
import argparse
On line 106, we call the main
() function if this is the file being executed:
if __name__ == '__main__':
main()
On line 70, we define the main
() function and call a function called parse_args()
and store that into a variable called args
:
def main():
args = parse_args()
This pattern is extremely common across both command line and GUI applications that take command line arguments.
The parse_args() function, as you can guess, parses the command line arguments and returns them. It starts with creating a argparse.ArgumentParser
object, passing in a description of the program:
def parse_args():
parser = argparse.ArgumentParser(
description="This gives examples of how to use argparse."
)
At the end of parse_args(), on line 67, it returns the output of parser.parse_args()
:
return parser.parse_args()
If we put all that code together, we would have the following:
import argparse
def parse_args():
parser = argparse.ArgumentParser(
description="This gives examples of how to use argparse."
)
return parser.parse_args()
def main():
args = parse_args()
if __name__ == '__main__':
main()
If we named the file file argparse_example.py
, and ran it with:
python argparse_example.py -h
We would get the following output:
usage: argparse_example.py [-h]
This gives examples of how to use argparse.
optional arguments:
-h, --help show this help message and exit
As you can see, by doing the basic setup, we already get the -h
flag. Now onto setting up some args!
Positional Arguments
The type of argument we are going to setup is a positional argument. This is an argument that you pass after the command name that doesn’t have a “-” or “–” in front of it. You can have multiple of them and differentiates them based on their position (thus the name positional argument).
Starting on line 8, we add an argument with parser.add_argument()
, that is named "echo"
, and we give it the help text "Echo the string you use here"
.
# Positional argument
parser.add_argument(
"echo",
help="Echo the string you use here"
)
Before doing anything else, lets add that code and run python argparse_example.py -h
again to see what we get for the help output:
usage: argparse_example.py [-h] echo
This gives examples of how to use argparse.
positional arguments:
echo Echo the string you use here
optional arguments:
-h, --help show this help message and exit
You can see from the output above, it recognizes echo
as a positional argument, shows it’s help text, and shows an example usage of the command.
And down in the main function we can add some code to actually use the echo
positional argument:
print("echo: {}".format(args.echo))
If we put that together and run the following command:
python argparse_example.py test
We get the following output:
echo: test
From line 74, you can see that we can access the named arg echo
by just doing args.echo
. This pattern of args.<NAME_OF_ARG>
can be used for all named arguments.
Something to note: Positional args by default are required when running the command. If they are not provided, the program will error. For example, if you run:
python argparse_example.py
You get the following output:
usage: argparse_example.py [-h] echo
argparse_example.py: error: the following arguments are required: echo
Optional Arguments
Next we add an optional argument. They start with a “–” or a “-“. In our example we add the --name
argument:
# Optional argument
parser.add_argument(
"--name",
help="Give me a name.",
action="store"
)
We give it some help text and we also pass it the action "store"
. To quote the argparse
documentation:
The action keyword argument specifies how the command-line arguments should be handled
"store"
is the default action and it will store whatever comes after the optional argument.
Note: There are a lot more actions than "store"
. We will cover a few here but for a comprehensive list, see the documentation.
To finish off this example, in the main we print out the name
arg:
if args.name:
print("name: {}".format(args.name))
And to test it, if we run the command:
python argparse_example.py test --name Bob
We get the following output:
echo: test
name: Bob
Note: If you want to pass a string with spaces in it, you need to wrap it in quotes. For example, if you wanted to pass "Bob Smith"
for the --name
argument, the command would be:
python argparse_example.py test --name "Bob Smith"
And you would get the following output:
echo: test
name: Bob Smith
store_true
One of the other really useful actions is "store_true"
. This allows you to pass an optional argument with nothing after it and just know that it was set. For example, on line 21 we add the "--switch_on"
argument setting the action to "store_true"
:
# Action store_true: Useful for when you want a yes or a no
parser.add_argument(
"--switch_on",
help="To turn the switch on.",
action="store_true"
)
And in the main to show it works we added the following:
print("action store_true: {}".format(args.switch_on))
And to test it, if we run the command:
python argparse_example.py test --switch_on
We get the following output:
echo: test
action store_true: True
By default, if you do not pass the program an optional argument that has it’s action set to “store_true”, the argument will be set to False. For example, if we run:
python argparse_example.py test
We get the following output:
echo: test
action store_true: False
Converting Inputs
By default, arguments are returned as strings, but you can pass anything callable (like a function) that takes in a string to pass to the type
keyword. For example, lets get an int
from an optional argument named --count
:
# Getting other types of input by conversion
parser.add_argument(
"--count",
help="Give me a number.",
type=int
)
And in the main to show it works we added the following:
if args.count:
print("count: {}".format(args.count))
print("type(count): {}".format(type(args.count)))
And to test it, if we run the command:
python argparse_example.py test --count 10
We get the following output:
echo: test
action store_true: False
count: 10
type(count): <class 'int'>
As from the test above, you can see that args.count
returned an object of type int
. More examples of what you can pass to type
can be found in the documentation.
Making Optional Arguments Required
Going against the name optional in optional argument, it is possible to make an optional argument required, by setting required=True
as seen below:
# Making it required
parser.add_argument(
"--last_name",
help="Your last name.",
required=True
)
And in the main to show it works we added the following:
print("last_name: {}".format(args.last_name))
And to test it, if we run the command:
python argparse_example.py test --last_name Smith
We get the following output:
echo: test
action store_true: False
last_name: Smith
While this is sometimes useful, as noted in the documentation:
Required options are generally considered bad form because users expect options to be optional, and thus they should be avoided when possible.
Multiple Inputs with nargs=”*”
Sometimes we want to input a list of things for an argument. This can be accomplished with nargs
. Specifically if we give nargs="*"
, that means we will take 0 or more items in for this argument. For example, if we wanted a flag that could take a list of number and add them together we could do the following:
# Multiple inputs with nargs="*"
parser.add_argument(
"--add",
help="Add the following numbers.",
type=int,
nargs="*"
)
And in the main to show it works we added the following:
if args.add:
print("add: {}".format(args.add))
print("sum(add) = {}".format(sum(args.add)))
And to test it, if we run the command:
python argparse_example.py test --last_name Smith --add 1 2 3
We get the following output:
echo: test
action store_true: False
last_name: Smith
add: [1, 2, 3]
sum(add) = 6
As you can see from the code and output, args.add
is a list of int
‘s because we used a combination of type=int
and nargs="*"
.
Multiple Inputs with nargs=”+”
It is legal to pass zero things to the --add
flag. If we want to force it to take one or more (and error if you pass zero), you can use nargs="+"
. For example, we can have a new flag named count that will take in 1 or more int’s:
# Multiple input with nargs="+"
parser.add_argument(
"--numbers",
help="Give me at least one number.",
type=int,
nargs="+"
)
And in the main to show it works we added the following:
print("numbers: {}".format(args.numbers))
And to test it, if we run the command:
python argparse_example.py test --last_name Smith --numbers 4 5 6
We get the following output:
echo: test
action store_true: False
last_name: Smith
numbers: [4, 5, 6]
And if you tried it with 0 things passed to --numbers
like so:
python argparse_example.py test --last_name Smith --numbers
It errors giving you the following output:
usage: argparse_example.py [-h] [--name NAME] [--switch_on] [--count COUNT] --last_name LAST_NAME [--add [ADD ...]] [--numbers NUMBERS [NUMBERS ...]] echo
argparse_example.py: error: argument --numbers: expected at least one argument
Bonus: Key Value Pairs as Input
Sometimes it can be very useful to take in complex input as command line arguments. One of the best ways I have found to do this is through key value pairs. This isn’t directly supported through argparse but here is a way to accomplish it:
### BONUS CONTENT ###
# Key Value pairs as input
parser.add_argument(
"--pairs",
metavar="KEY=VALUE",
nargs='*',
help="Create a set of key-value pairs."
)
We are adding a new argument called --pairs
. We set nargs="*"
so we can take zero or more items for the –pairs argument. We also use a new keyword argument metavar
.
When we print out the help text, the text needs a way to refer to the value that is passed with the argument. For example here is the help text up to the --name
flag:
usage: argparse_example.py [-h] [--name NAME] [--switch_on] [--count COUNT] --last_name LAST_NAME [--add [ADD ...]] [--numbers NUMBERS [NUMBERS ...]] [--pairs [KEY=VALUE ...]] echo
This gives examples of how to use argparse.
positional arguments:
echo Echo the string you use here
optional arguments:
-h, --help show this help message and exit
--name NAME Give me a name.
For --name
the value passed with it is displayed as NAME
. This value is called the metavar
. By default it is the name of the argument in all caps but you can change it to be whatever you want with the keyword argument metavar
. In this case, for —pairs
, we are setting metavar="KEY=VALUE"
. That means that its help text will look like this:
--pairs [KEY=VALUE ...]
Create a set of key-value pairs.
This is to indicate to the user the format of the input we expect. We expect a KEY
, a equals sign, and then the VALUE
.
And in the main to show it works we added the following:
if args.pairs:
print("pairs: {}".format(args.pairs))
print("parsed pairs: {}".format(parse_pairs(args.pairs)))
def parse_pairs(pairs):
d = {}
for pair in pairs:
items = pair.split("=")
d[items[0]] = items[1]
return d
As you can see above, outside of the main
we also added a new function called parse_pairs()
. This is to convert the pairs to a dictionary so that the data is much more usable. The key/value pairs just come in as a single string each, that we can split on the equals sign to get a key and a value.
And to test it, if we run the command:
python argparse_example.py test --last_name Smith --pairs fruit=pear number=2 letter=z
We get the following output:
echo: test
action store_true: False
last_name: Smith
numbers: None
pairs: ['fruit=pear', 'number=2', 'letter=z']
parsed pairs: {'fruit': 'pear', 'number': '2', 'letter': 'z'}
Note: Similar to previous arguments, if you want to pass a string with spaces in it as a key or value, you need to wrap it in quotes. For example, you could have the following command:
python argparse_example.py test --last_name Smith --pairs "fruity pebbles"=pear number="number two" "letter a"="z bee"
And you would get the following output:
echo: test
action store_true: False
last_name: Smith
numbers: None
pairs: ['fruity pebbles=pear', 'number=number two', 'letter a=z bee']
parsed pairs: {'fruity pebbles': 'pear', 'number': 'number two', 'letter a': 'z bee'}
While this allows you to use spaces in your key/value input, notice that the outputted keys and values have had their quotes stripped out. Be weary of that.
With everything above, that should cover the majority of your command line argument needs, but there is even more you can do. Check out the argparse
documentation for more details.