Is it possible to use more than one name to refer to a single argument in argparse?
Specifically, I want to allow user to specify an argument by either underscore and hyphen (dash)?
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--input-file')
args = parser.parse_args()
For example, I want both of the following options to work for the argument args.input_file:
python main.py --input-file /tmp/file
python main.py --input_file /tmp/file
Simply listing more options in .add_argument():
arg_parser.add_argument('--input-file', '--input_file')
should do the trick.
Note that using a minus - character in your argument is the preferred GNU syntax.
Related
I need to pass arguments directly to a command executed in my python script. The script itself does not need to evaluate or manipulate the arguments to be passed to the command.
./cookbooks.py vendor -o "--delete"
Unfortunately, argparse recognizes the -- in the quoted string as an attempt to provide an optional argument instead of a value and an error is returned, "error: argument -o/--options: expected one argument". It considers no value was provided for -o.
I simply want to append whatever is passed and not hinder the operators ability to use the underlying command. In below snippet, the options variable is supposed to be the quoted value of whatever.
cmd = ' '.join(["berks", "vendor", dir, options])
subprocess.call(cmd, cwd=entry.path, shell=True)
My parse argument is defined as below. I have also tried with type=str.
parser.add_argument("-o", "--options",
help="berks vendor or knife cookbook upload options passed directly to the command")
Is it possible to indicate to argparse to accept quoted values as is?
With your current definition, you can call your script with
./cookbooks.py vendor -o=--delete
Since -- doesn't start an argument, argparse doesn't see it as an option, only as part of a name-value pair to split on =.
I have the following command line tool:
import argparse
parser = argparse.ArgumentParser(description = "A cool application.")
parser.add_argument('positional')
parser.add_argument('--optional1')
parser.add_argument('--optional2')
args = parser.parse_args()
print args.positionals
The output of python args.py is:
usage: args.py [-h] [--optional1 OPTIONAL1] [--optional2 OPTIONAL2]
positional
however I would like to have:
usage: args.py [-h] positional [--optional1 OPTIONAL1] [--optional2 OPTIONAL2]
How could I have that reordering?
You would either have to provide your own help formatter, or specify an explicit usage string:
parser = argparse.ArgumentParser(
description="A cool application.",
usage="args.py [-h] positional [--optional1 OPTIONAL1] [--optional2 OPTIONAL2]")
The order in the help message, though, does not affect the order in which you can specify the arguments. argparse processes any defined options left-to-right, then assigns any remaining arguments to the positional parameters from left to right. Options and positional arguments can, for the most part, be mixed.
With respect to each other the order of positionals is fixed - that's why they are called that. But optionals (the flagged arguments) can occur in any order, and usually can be interspersed with the postionals (there are some practical constrains when allowing variable length nargs.)
For the usage line, argparse moves the positionals to the end of the list, but that just a display convention.
There have been SO questions about changing that display order, but I think that is usually not needed. If you must change the display order, using a custom usage parameter is the simplest option. The programming way requires subclassing the help formatter and modifying a key method.
I want to use '=' as argument separator and didn't get any option in library documentation. So, '=' supported as a argument separator/deliminator by argparse.
class Parse:
def __init__(self):
parser = argparse.ArgumentParser()
parser.add_argument("script_config",help="Script Config File")
parser.add_argument("devices",help="devices")
parser.add_argument("log_file",help="log_file")
parser.add_argument("result_file",help="result_file")
parser.add_argument("testbed_file",help="testbed_file")
parser.add_argument("runtime",help="Just Runetime")
args = parser.parse_args()
print pprint.pprint(args)
a=Parse()
Output to above code, Here I got runtime as runtime=10.
root#ip-:~/cloudzelera/$ python ../lib/TestsuiteOption.py /tmp/abc.conf qa05__lnx1__i-12b651ea /tmp/123.suite /tmp/result.tmp /tmp/config runtime=10
Namespace(devices='qa05__lnx1__i-12b651ea', log_file='/tmp/123.suite', result_file='/tmp/result.tmp', runtime='runtime=10', script_config='/tmp/abc.conf', testbed_file='/tmp/config')
None
runtime is not an optional argument, it is a required, positional argument. As such you'd never use the name on the command line:
TestsuiteOption.py /tmp/abc.conf qa05__lnx1__i-12b651ea /tmp/123.suite /tmp/result.tmp /tmp/config 10
If you want runtime to be optional, start the option with two dashes (for a long name):
parser.add_argument("--runtime", help="Just Runtime")
and use the same on the command line:
TestsuiteOption.py /tmp/abc.conf --runtime=10 qa05__lnx1__i-12b651ea /tmp/123.suite /tmp/result.tmp /tmp/config
Now the option can be used anywhere on the command line, including at the start.
Note that argparse uses the UNIX convention of command line arguments, where optional arguments start with - for short 1-character arguments, -- for long arguments. It is not suitable for other conventions.
Given that what you have specified is not compliant with the Unix argument parsing conventions, why have another line at the end where you would do:
args.runtime = args.runtime.split('=')[1]
I cannot figure out this behaviour of argparse from the documentation:
import argparse
parser.add_argument("--host", metavar="", dest="host", nargs=1, default="localhost", help="Name of host for database. Default is 'localhost'.")
args = parser.parse_args()
print(args)
Here is the output with and without an argument for "--host":
>> python demo.py
Namespace(host='localhost')
>> python demo.py --host host
Namespace(host=['host'])
In particular: why does the argument to "--host" get stored in a list when it is specified but not when the default is used?
Remove the "nargs" keyword argument. Once that argument is defined argparse assumes your argument is a list (nargs=1 meaning a list with 1 element)
As an alternative and handy module: Docopt can be used for parsing command line arguments. Docopt transform a commandline into a dictionnary by defining values inside doc.
The question title and the question body ask two different questions. This is potentially a sign of the confusion I shared with the OP.
The title: why is the default a string not a list?
The body: why is the given value a list not a string?
The selected answer provides the solution to the question in the body. The answer to the question in the title is:
The entry default="localhost" sets default to "localhost", which is a sting. To set it as a list, you could use: default=["localhost"].
In python argparse, is it possible to declare an argument which is just single-valued, instead a list, but allows being specified multiple times, the latest one overrides the earlier ones?
The use case is, I am writing a Python program that reads command line argument from a ~/.xxxrc file, where .xxxrc file has an command line argument per line. I want to allow user override the value in ~/.xxxrc file through command line. My plan is to implicitly adds an #~/.xxxrc to the beginning of argv before passing it to argparse, so that argparse will reads in the file. Now the problem turns into my question above.
Is it possible to achieve this effect? If not, is there any alternative solution to my use case.
The argparse module does that by default. Take a look at this example, where we specify the same flag twice, and the last one wins:
import argparse
parser = argparse.ArgumentParser(description='example')
parser.add_argument('-a', '--add')
options = parser.parse_args(['-a', 'foo', '-a', 'bar'])
print 'add = {}'.format(options.add) # output: add = bar
Yes, you can just create a custom action with an nargs='*' or nargs='+'.
Something like this should work:
class GetLastAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if values:
setattr(namespace, self.dest, values[-1])
parser = argparse.ArgumentParser()
parser.add_argument('-a', nargs='+', action=GetLastAction)