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
Related
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.
I have the following snippet:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--p', required=True)
parser.add_argument('arg', action=MyAction)
parser.parse_args()
, where MyAction is a simple custom action class.
As you see, I want to enforce the presence of the p argument. However, my action is performed even if the argument is not present, and then an error message is shown that indicates the fact the the argument is missing.
Obviously, I could check in my action class for the presence of the p argument, but this defies the purpose of having a required parameter in the first place. Why is my action being run if the argument is not present?
Parsing is driven by the commandline strings, and tries to be order agnostic. Within those rules, it alternates between parsing an optional and a positional.
For example, with myprog --p one two:
'--p' - pass the 'one' string to the p action (e.g. setattr(namespace, 'p', 'one')
'two' - matches the nargs for 'arg'. Calls your MyAction.__call__ with values='one'.
at the end of parsing it checks if all required actions have been 'seen'. With your setup both '--p' and 'arg' are required.
With myprog two --p one it does the same, except arg is processed first. The namespace may have a default value for p.
With myprog two, arg is processed, and the required test will raise an error. error: the following arguments are required: --p
Since you have written a custom Action, you can easily explore how the namespace contents vary depending on the commandline arguments and their order.
So the --p and the arg will be processed independently, and in either order, depending on the commandline strings. required testing is performed at the end, using a list of seen_actions. And default values are set at the start of parsing. It is difficult to implement reliable inter-action tests within custom Actions. Usually it is better to perform such tests after parsing.
The defined Actions only change the args namespace. So parsing does not change anything beyond what it returns. Unless there's an error and it forces an sys.exit. A custom MyAction class can change that, but at your own risk.
I have a small program that uses argparse and a positional argument. I'm trying to allow that argument to be set by using an environment variable, but are not getting it to work.
I have seen this post: Setting options from environment variables when using argparse which mentions the same problem, but not for positional arguments.
This is the code so far:
import argparse
import os
class EnvDefault(argparse.Action):
def __init__(self, envvar, required=True, default=None, **kwargs):
if not default and envvar:
if envvar in os.environ:
default = os.environ[envvar]
if required and default:
required = False
super(EnvDefault, self).__init__(default=default, required=required, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('testvar', help="Test variable", action=EnvDefault, envvar='TEST_VAR')
parser.add_argument('--othervar', help="Other variable", action='store_true')
args = parser.parse_args()
if not args.testvar: exit(parser.print_usage())
print args.testvar
Which returns this:
$ TEST_VAR="bla" ./test.py
usage: test.py [-h] [--othervar] testvar
test.py: error: too few arguments
You need to make positional argument optional, try nargs='?':
...
parser.add_argument('testvar', help="Test variable", action=EnvDefault,
envvar='TEST_VAR', nargs='?')
...
Note that output changes slightly:
$ python test.py
usage: test.py [-h] [--othervar] [testvar]
Note: There's one side effect - it doesn't return error, even if env variable is not set.
The too few error message indicates that you have slightly older version of Python/argparse. Here's the code that generates the message. It occurs at the end of parsing:
# if we didn't use all the Positional objects, there were too few
# arg strings supplied.
if positionals:
self.error(_('too few arguments'))
# make sure all required actions were present
for action in self._actions:
if action.required:
if action not in seen_actions:
name = _get_action_name(action)
self.error(_('argument %s is required') % name)
positionals starts a list of all the positional arguments, which are removed as they get matched up with argument strings. So it is testing if any were not matched.
Note that the test of the required attribute occurs after this positional test, so changing it, as your Action does, does not help.
The only way to make a positional optional is with nargs - ? or *. An empty list of strings matches those, so such a positional is always consumed.
Check the docs for these. The const parameter might be useful.
The latest version drops that if positionals test, using only the required test to generate a list of arguments that were not used. Your special Action might work in that code.
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 would like to be able to specify an option to my program which acts as both a flag and as variable. For example:
I have an argument called "--logging". If this argument is not specified, I'd like it to be set to false (i.e. action='store_true'), but if the argument is specified, I'd like to do two things. 1) I'd like to set a default path of "./log_file.log" and 2) I'd like to allow the user to specify a different log file location.
Right, so I've come up with my own solution for this one. It relies on nargs. Here is the code first:
#!/usr/bin/python
# example.py
import argparse
parser = argparse.ArgumentParser(description="Example of a single flag acting as a boolean and an option.")
parser.add_argument('--foo', nargs='?', const="bar", default=False)
args = parser.parse_args()
if args.foo:
print args.foo
else:
print "Using the default, boolean False."
Given that example, here is what happens when we use it in the three possible situations:
> ./example.py
Using the default, boolean False.
> ./example.py --foo
bar
> ./example.py --foo baz
baz
Hopefully the above is pretty self-explanatory. In case it isn't, what is going on is that nargs='?' will use the 'default' value if the flag is not specified (boolean False in our case), the const value if the flag is specified without arguments, and the argument if the flag is specified with an argument. Be careful to not put any quotes around False; False is a built in type (boolean) and 'False' or "False" will evaluate as true.
Yes there is no issue. You can use this form explained in the excellent PyMOTW about argparse
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--logging', action='store_true', default=False,
dest='logging_on',
help='Activate the logging')
results = parser.parse_args()
You can use the logging_on to test and output values later on in your code (replace it by what makes sense for you). You can also use either a config file or/and an argument for the file log path.