How to use '=' as an argument separator using argparse Python? - python

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]

Related

argparse with optional value with quoted "--options --for --other --cmd"

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 =.

argparse: How to allow multiple names for single argument?

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.

How to use optional argumnets without - or --(dash)

i want to use the optional arguments without - or --,
want to achive something like this:
scriptname install <other options>
scriptname uninstall <other options>
my code:
parser = argparse.ArgumentParser()
parser.add_argument("install","INSTALL",action='store_true',help="INSTALL SOMETHING",default="")
parser.add_argument("uninstall","UNINSTALL",action='store_true',help="UNINSTALL SOMETHING",default="")
args = parser.parse_args()
if args.install:
install logic
if args.uninstall:
uninstall logic
getting the error below
ValueError: invalid option string 'install': must start with a character '-'
A 'store_true' action does not take any arguments (nargs=0). A positional with that action is always true. And it will reject commandline strings like 'install' as unrecognized.
The dash is part of the definition of an optional. It identifies strings that serve as flags or names, as opposed to values. Without it you are defining a positional, an argument that is identified by position rather than a flag string.
So the normal optionals definitions would be:
parser.add_argument("--install",action='store_true',help="INSTALL SOMETHING")
parser.add_argument("--uninstall",action='store_true',help="UNINSTALL SOMETHING")
You could put those in a mutually exclusive group. With store_true the default is False, and if the flag is provided, without any argument, the attribute is set of True.
store_true is allowed with positionals, but doesn't make sense. A positional is required, so you can't get a False value.
You could define a positional with choices:
parser.add_argument('foo', choices=['install', 'uninstall'], help='...')
Then args.foo will have ones of those two string values.
The suggested use of subparsers is a variant on this choices positional - one where the action type is a special one that triggers a new parser.
What about using "sys" module instead of "argparse"? Then answer would be
import sys
if sys.argv[1] == "install":
install logic
elif sys.argv[2] == "uninstall":
uninstall logic
else:
exit

'argparse' with optional positional arguments that start with dash

We're trying to build a wrapper script over a command line tool we're using. We would like to set some tool arguments based on options in our wrapper scripts. We would also like to have the possibility to pass native arguments to the command line tool directly as they are written on the command line.
Here is what we came up with:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('positional')
parser.add_argument('-f', '--foo', action='store_true')
parser.add_argument('-b', '--bar', action='store_true')
parser.add_argument('native_arg', nargs='*')
args = parser.parse_args()
print (args)
positional is mandatory. Based on the options -f and -b we would add some extra options to our tool call. Anything that is left afterwards (if anything) should be treated as a native tool argument and given to the tool directly. Calling our script with -h produces the following usage:
usage: test.py [-h] [-f] [-b] positional [native_arg [native_arg ...]]
The trick is that these native arguments are themselves options for the tool and contain leading dashes, for example -native0 and -native1. We already know about the trick with the double dash to stop argparse from looking for more options. The following call:
./test.py pos -- -native0 -native1
produces the expected parsed arguments:
Namespace(bar=False, foo=False, native_arg=['-native0', '-native1'], positional='pos')
Trying to add an option after the first positional argument doesn't work, though. More specifically, the following call:
./test.py pos --foo -- -native0 -native1
produces the following output:
usage: [...shortened...]
test.py: error: unrecognized arguments: -- -native0 -native1
Putting the optional arguments before the positionals:
./test.py --foo pos -- -native0 -native1
seems to work, as the following is printed:
Namespace(bar=False, foo=True, native_arg=['-native0', '-native1'], positional='pos')
Even stranger, changing the value of nargs for native_arg to '+' works in all the above situations (with the caveat, of course, that at least one native_arg is expected).
Are we doing something wrong in our Python code or is this some kind of argparse bug?
argparse does have a hard time when you mix non-required positional arguments with optional arguments (see https://stackoverflow.com/a/47208725/1399279 for details into the bug report). Rather than suggesting a way to solve this issue, I am going to present an alternative approach.
You should check out the parse_known_args method, which was created for the situation you describe (i.e. passing options to a wrapped tool).
In [1]: import argparse
In [2]: parser = argparse.ArgumentParser()
In [3]: parser.add_argument('positional')
In [4]: parser.add_argument('-f', '--foo', action='store_true')
In [5]: parser.add_argument('-b', '--bar', action='store_true')
In [6]: parser.parse_known_args(['pos', '--foo', '-native0', '-native1'])
Out[6]: (Namespace(bar=False, foo=True, positional='pos'), ['-native0', '-native1'])
Unlike parse_args, the output of parse_known_args is a two-element tuple. The first element is the Namespace instance you would expect to get from parse_args, and it contains all the attributes defined by calls to add_argument. The second element is a list of all the arguments not known to the parser.
I personally prefer this method because the user does not need to remember any tricks about how to call your program, or which option order does not result in errors.
This is a known issue (https://bugs.python.org/issue15112, argparse: nargs='*' positional argument doesn't accept any items if preceded by an option and another positional)
The parsing alternates handling positionals and optionals. When dealing with positionals it tries to handle as many as the input strings require. But an ? or * positional is satisfied with [], an empty list of strings. + on the other hand requires at least one string
./test.py pos --foo -- -native0 -native1
The parser gives 'pos' to positional, and [] to native-arg. Then it gives '--foo' to its optional. There aren't anymore positionals left to hand the remaining strings, so it raises the error.
The allocation of input strings is done with a stylized form of regex string matching. Imagine matching a pattern that looks like AA?.
To correct this, parser would have to look ahead, and delay handling native-arg. We've suggested patches but they aren't in production.
#SethMMorton's suggestion of using parse_known_args is a good one.
Earlier parsers (e.g. Optparse) handle all the flagged arguments, but return the rest, the positionals, as a undifferentiated list. It's up to the user to split that list. argparse has added the ability to name and parse positionals, but the algorithm works best with fixed nargs, and gets flaky with too many variable nargs.

Defining the order of the arguments with argparse - Python

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.

Categories

Resources