Reputation: 55
I'm looking for a way to make a commandline option with optional argument using optparse
Python module.
For example there are two command lines: foobar -u -v
and foobar -u USERNAME -v
. While latter gets USERNAME
as an argument, former should detect absence of an argument and get username from the environment variable or by other means, and not treat -v
as an argument, but as an option instead.
I know there is possibility to take multiple arguments using append
action, but it requires at least one argument.
Are there any solutions?
UPDATE:
Why won't this script works if no arugment is provided ? I have given some value to Default also. Cannot something like this can used ?
#!/usr/bin/env python
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-u", "--user", dest="in_dir",
help="write report to FILE", action= "store", default='USERNAME')
(options, args) = parser.parse_args()
if options.in_dir == 'USERNAME':
print' argument supplied or taken from default '
else:
print 'arugment supplied'
On executing this file we get ./options.py -f Usage: options.py [options]
options.py: error: -f option requires an argument
As I have given some values in the default. Why cannot it take that value from there ? Is any there other solution to this?
Upvotes: 1
Views: 3358
Reputation: 1529
There is an example in the optparse documentation that does something similar through a callback.
If the ambiguities are easy to sort out, e.g., because the optional argument is an int, you can use the following that is essentially copied over from SageMath's sage-runtest
script.
import optparse
def optional_argument(option, opt_str, value, parser, typ, default_arg):
try:
next_arg = typ(parser.rargs[0])
except Exception:
next_arg = default_arg
else:
parser.rargs.pop(0)
setattr(parser.values, option.dest, next_arg)
parser = optparse.OptionParser()
parser.add_option('-n',
'--number',
dest='n',
default=-1,
action="callback",
callback=optional_argument,
callback_args=(int, -2),
nargs=0)
With this you get:
>>> parser.parse_args()
(<Values at ...: {'n': -1}>, [])
>>> parser.parse_args(['-n'])
(<Values at ...: {'n': -2}>, [])
>>> parser.parse_args(['-n', 42])
(<Values at ...: {'n': 42}>, [])
Note that you would need to explicitly mention the optional parameter in the documentation; optparse, renders the help as if this parameter took no arguments:
>>> parser.print_help()
...
Options:
-h, --help show this help message and exit
-n, --number
Upvotes: 0
Reputation: 76
Maybe you could inspect sys.argv
before adding the -u
option to your parser. If the next element on sys.argv
(following -u
) is not a username, then you could insert the username into the list before parsing. Something like the following code :
import sys
from optparse import OptionParser as OP
cmdLine = sys.argv
i = cmdLine.index('-u')
if (i+1) == len(cmdLine) or cmdLine[i+1] not in users:
cmdLine.insert(i+1,userName)
p = OP()
p.add_option('-u',action='append')
p.parse_args(cmdLine[1:])
Upvotes: 1
Reputation: 148900
AFAIK there is no solution with the optparse
module. Extract from The Python Standard Library (same for Python 2 2 and 3):
Typically, a given option either takes an argument or it doesn’t. Lots of people want an “optional option arguments” feature, meaning that some options will take an argument if they see it, and won’t if they don’t. This is somewhat controversial, because it makes parsing ambiguous: if -a takes an optional argument and -b is another option entirely, how do we interpret -ab? Because of this ambiguity, optparse does not support this feature.
You could have more luck with the newer argparse
module that explicitely support that kind of requirement. Extracts from The Python Standard Library for argparse
The add_argument() method
ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
Define how a single command-line argument should be parsed. Each parameter has its own more detailed description below, but in short they are:
...
nargs - The number of command-line arguments that should be consumed.
...
and later in nargs
description :
'?'. One argument will be consumed from the command line if possible, and produced as a single item. If no command-line argument is present, the value from default will be produced.
Upvotes: 0