I recently needed to handle some arguments for a command line Python program. I considered using the built in sys.argv approach, but decided that it would be better to experiment with the argparse library. Along the way I found a few useful hints and tricks that might prove useful to others.

First Things First
It seems that argparse is not available via Anaconda so use pip install argparse to install and import argparse to import.
To use argparse in your code there are basically three main commands you will use:
import argparse # 1 - create our argument parser object parser = argparse.ArgumentParser(...) # 2 - add any arguments we want to process, # more on the parameters you will need later parser.add_argument(...) # we will likely use add_argument() multiple times ... # 3 - process our received arguments out into a useable form arguments = parser.parse_args()
You get a few nice quality of life benefits from argparse almost for free. One of these is that you can easily add help instructions which will be called when you run python file.py -h. You do this by adding a description parameter to ArgumentParser() and a help parameter to add_argument(). Another thing you can do is validate inputs by specifying a type in add_argument() as shown below. Additionally handling multiple switches like -v and –verbose is easy in argparse.
How To Use add_argument
The core of using argparse is adding the arguments using add_argument(). The official documentation is verbose and a little hard to follow so I shall break down a few of my key findings here
you can have one variable which does not have a keyword and can take a variable number of arguments as desired. These arguments must be typed first in the argument list when invoking:
parser.add_argument(
'paths',
metavar='N', # this means the variable is positional
type=str, # specify our type
nargs='*', # ? is zero or one, * is zero or more, + is one or more
help='File or folder paths.',
)
creating a simple flag variable can be done like this:
# note that we specify both '-v' and '--verbose'
parser.add_argument(
'-v',
'--verbose',
action='store_true', # this converts to a flag
help='Display intermediate steps in processing',
)
creating a variable which can take parameters can be achieved like this:
parser.add_argument(
'-s',
'--save',
required = False, # allows for omission
type = str,
nargs='?', # allows zero or more parameters
default = None, # defaults to None for zero parameters
help='Save data to specified folder',
)
And for basic usage that is about it. These three constructions should let you get started. I have included some more reading below for more advanced functions but this is a good starting point.
Testing argparse
But how do we test a function which relies on arguments being passed in at runtime? The fgood news is that it is actually remarkably simple. First wrap your arg parse code in a function. Then pass that function the sys.argv arguments it relies on under the hood explicitly rather than allowing it to pick them up implicitly. This then allows you to test your function using pytest or your other prefered testing framework. To do this just pass known arguments to your argument parsing function and test its returns.
import argparse
def parse_arguments(args):
parser = argparse.ArgumentParser(...)
parser.add_argument(...)
# ...Create your parser as you like...
return parser.parse_args()
# omit the first sys.argv since that is the program file
parser = parse_arguments(sys.argv[1:])
# tests would be of the form
import pytest
class TestArgParser:
def test_arparse_verbose(self, ):
parser = parse_arguments(['-v'])
assert parser.verbose is True
Other Reading
The official argparse documentation can be found here: https://docs.python.org/2.7/library/argparse.html
There are also a couple of good quick start guides that go into the subject in more detail than this article including dealing with mutually exclusive options and creating subparsers :
https://docs.python.org/3/howto/argparse.html#
https://towardsdatascience.com/a-simple-guide-to-command-line-arguments-with-argparse-6824c30ab1c3
Finally my testing approach was shamelessly stolen from stackoverflow