What's the best way to parse command line arguments?
Solution 1
This answer suggests optparse
which is appropriate for older Python versions. For Python 2.7 and above, argparse
replaces optparse
. See this answer for more information.
As other people pointed out, you are better off going with optparse over getopt. getopt is pretty much a one-to-one mapping of the standard getopt(3) C library functions, and not very easy to use.
optparse, while being a bit more verbose, is much better structured and simpler to extend later on.
Here's a typical line to add an option to your parser:
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
It pretty much speaks for itself; at processing time, it will accept -q or --query as options, store the argument in an attribute called query and has a default value if you don't specify it. It is also self-documenting in that you declare the help argument (which will be used when run with -h/--help) right there with the option.
Usually you parse your arguments with:
options, args = parser.parse_args()
This will, by default, parse the standard arguments passed to the script (sys.argv[1:])
options.query will then be set to the value you passed to the script.
You create a parser simply by doing
parser = optparse.OptionParser()
These are all the basics you need. Here's a complete Python script that shows this:
import optparse
parser = optparse.OptionParser()
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
options, args = parser.parse_args()
print 'Query string:', options.query
5 lines of python that show you the basics.
Save it in sample.py, and run it once with
python sample.py
and once with
python sample.py --query myquery
Beyond that, you will find that optparse is very easy to extend. In one of my projects, I created a Command class which allows you to nest subcommands in a command tree easily. It uses optparse heavily to chain commands together. It's not something I can easily explain in a few lines, but feel free to browse around in my repository for the main class, as well as a class that uses it and the option parser
Solution 2
argparse
is the way to go. Here is a short summary of how to use it:
1) Initialize
import argparse
# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')
2) Add Arguments
# Required positional argument
parser.add_argument('pos_arg', type=int,
help='A required integer positional argument')
# Optional positional argument
parser.add_argument('opt_pos_arg', type=int, nargs='?',
help='An optional integer positional argument')
# Optional argument
parser.add_argument('--opt_arg', type=int,
help='An optional integer argument')
# Switch
parser.add_argument('--switch', action='store_true',
help='A boolean switch')
3) Parse
args = parser.parse_args()
4) Access
print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)
5) Check Values
if args.pos_arg > 10:
parser.error("pos_arg cannot be larger than 10")
Usage
Correct use:
$ ./app 1 2 --opt_arg 3 --switch
Argument values:
1
2
3
True
Incorrect arguments:
$ ./app foo 2 --opt_arg 3 --switch
usage: convert [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
app: error: argument pos_arg: invalid int value: 'foo'
$ ./app 11 2 --opt_arg 3
Argument values:
11
2
3
False
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
convert: error: pos_arg cannot be larger than 10
Full help:
$ ./app -h
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
Optional app description
positional arguments:
pos_arg A required integer positional argument
opt_pos_arg An optional integer positional argument
optional arguments:
-h, --help show this help message and exit
--opt_arg OPT_ARG An optional integer argument
--switch A boolean switch
Solution 3
Using docopt
Since 2012 there is a very easy, powerful and really cool module for argument parsing called docopt. Here is an example taken from its documentation:
"""Naval Fate.
Usage:
naval_fate.py ship new <name>...
naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
naval_fate.py ship shoot <x> <y>
naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
naval_fate.py (-h | --help)
naval_fate.py --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.
"""
from docopt import docopt
if __name__ == '__main__':
arguments = docopt(__doc__, version='Naval Fate 2.0')
print(arguments)
So this is it: 2 lines of code plus your doc string which is essential and you get your arguments parsed and available in your arguments object.
Using python-fire
Since 2017 there's another cool module called python-fire. It can generate a CLI interface for your code with you doing zero argument parsing. Here's a simple example from the documentation (this small program exposes the function double
to the command line):
import fire
class Calculator(object):
def double(self, number):
return 2 * number
if __name__ == '__main__':
fire.Fire(Calculator)
From the command line, you can run:
> calculator.py double 10
20
> calculator.py double --number=15
30
Solution 4
The new hip way is argparse
for these reasons. argparse > optparse > getopt
update: As of py2.7 argparse is part of the standard library and optparse is deprecated.
Solution 5
I prefer Click. It abstracts managing options and allows "(...) creating beautiful command line interfaces in a composable way with as little code as necessary".
Here's example usage:
import click
@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
help='The person to greet.')
def hello(count, name):
"""Simple program that greets NAME for a total of COUNT times."""
for x in range(count):
click.echo('Hello %s!' % name)
if __name__ == '__main__':
hello()
It also automatically generates nicely formatted help pages:
$ python hello.py --help
Usage: hello.py [OPTIONS]
Simple program that greets NAME for a total of COUNT times.
Options:
--count INTEGER Number of greetings.
--name TEXT The person to greet.
--help Show this message and exit.
Related videos on Youtube
kamens
Lead dev at Khan Academy. Ex-VP of Engineering at Fog Creek. @kamens
Updated on August 08, 2020Comments
-
kamens over 3 years
What's the easiest, tersest, and most flexible method or library for parsing Python command line arguments?
-
matt wilkie about 13 yearsThis answer is wonderfully clear and easy to follow -- for python 2.3 thru 2.6. For python 2.7+ it is not the best answer as argparse is now part of the standard library and optparse deprecrated.
-
telotortium about 11 yearsThank you. This script helped me work out some really complicated quoting I needed to do when passing startup commands to GVim.
-
shuttle87 almost 10 yearsWith the deprecation of
getopt
in newer versions of Python this answer has gone out of date. -
Christophe Roussy over 8 yearsThis is very concise and useful and here is the official doc (for convenience): docs.python.org/3/library/argparse.html
-
keen almost 8 yearshow does docopt "need no installation" ? it's a python module so it does have to be installed. 'ImportError: No module named docopt'
-
ndemou almost 8 years@keen it's not included with python for sure but you don't need to install it: "you can just drop docopt.py file into your project--it is self-contained" -- github.com/docopt/docopt
-
keen almost 8 yearswe just have different definitions of install - and I wanted to point that out for future readers.
-
ndemou almost 8 years@keen I've added a note on "no installation" for people sharing your definition :-)
-
krassowski over 6 yearsI've developed a small package utilizing automatic arguments creation:
declarative_parser
. Of course, if one is working with werkzeug, it may be better to keep thewerkzung.script
. Anyway, I'm a huge fan of such approach. -
krassowski over 6 yearsI've used similar approach in declarative-parser, see arguments deduction (typing, docstrings, kwargs) in docs. Main differences: python3, type hints, pip-installable.
-
historystamp about 6 yearsthe quotes are mismatched in the def statement.
-
DisappointedByUnaccountableMod over 5 yearsPoint of information: the neatest use of plac (as shown in the example) is for Python 3.x only, because it uses 3.x function annotations.
-
Skippy le Grand Gourou about 5 years@shuttle87 As of python3.7.2,
getopt
is still not deprecated… But its documentation states that it is mainly provided for users familiar with the Cgetopt()
function, and acknowledges that for other usersargparse
might be a better solution, allowing to "write less code and get better help and error messages". -
Joe Holloway over 4 yearsYour main link is 404 so I replaced it with a link to a SO question that addresses the same topic.
-
Boris Verkhovskiy over 4 yearsLast commit in 2012
-
Yogeshwar Singh over 4 yearsIn my case, I want to profile my application to detect the slowness. There is another tool called [tuna] (github.com/nschloe/tuna) which allows me to profile the entire application by simply adding agrs
-mcProfile -o program.prof
but agrparcer is capturing these args, how to I pass these args to python exe??? -
Nimitz14 over 4 yearsIf you find argparse too verbose use plac instead.
-
jkulhanek over 2 yearsYou can also try github.com/jkulhanek/aparse which extends argparse or click with support for typing.
-
j.c about 2 years@nimitz14: the plac link you provided is not working.
-
Nimitz14 about 2 years