Problem: I have a parser that has 1 required arg and a subparser that accepts 3 args of which 2 are required when that sub parser is invoked
As follows
Code:
parser.add_argument("-f", "--foo", type=str, required=True, help="foo help")
subparsers=parser.add_subparsers(help="Sub parsers")
mysubparser = subparsers.add_parser("a", help="a subparser")
mysubparser.add_argument("-b", "--bar", type=str, required=True, help="bar help")
mysubparser.add_argument("-bz", "--baz", type=str, required=True, help="baz help")
mysubparser.add_argument("-bzg", "--bazinga", action="store_true", help="bazinga help")
What I tried:
my problem is that
python myscript.py -f "hi" a -b "hi" -bz "hi" works but python myscript.py a -b "hi" -bz "hi" -f "hi" doesn't. Do required args have to be specified first? I think it looks a bit clunky the first way. is there a way this can be fixed?
I want both versions to work. Or a better alternative to doing things this way
Related
I would like to have a code that get the first argument as tool and after that expects different options depending on the tool
myapp.py [TOOL] [TOOLPARAMETERS]
python myapp.py tool0 -i 'path/to/my_image.jpg' -o 'path/to/my_output_path_folder/' -r 0.7 -m 13
python myapp.py tool1 -m 3 -r 'some_string_now' -m 13
As you can see in this case each tool could have it's own required arguments and in each case they could even expect different types
I have been messing around with add_subparsers with some success.
import argparse
parser = argparse.ArgumentParser(prog='myapp', usage='%(prog)s [tool] [options]')
parser.add_argument('-a', required=True, help='required globally argument for all tools')
subparsers = parser.add_subparsers(help='tool help')
# subparser for tool0
parser_tool0 = subparsers.add_parser('tool0', help='tool 0 help')
# ADD tool0 ARGUMENTS
parser_tool0.add_argument('-i' , required=True, help='path to the input folder')
parser_tool0.add_argument('-o' , required=True, help='path to the output folder')
parser_tool0.add_argument('-r' , default=0.7, type=float, help='some float')
parser_tool0.add_argument('-g' , default=10, type=int, help='some integrer')
parser_tool0.add_argument('-d' , default=False, help='debug')
# subparser for tool1
parser_tool0 = subparsers.add_parser('tool1', help='tool 0 help')
# ADD tool0 ARGUMENTS
parser_tool0.add_argument('-r' , help='r not required string')
parser_tool0.add_argument('-f' , required=True, help='f not required string')
parser_tool0.add_argument('-d' , default=0.7, type=float, help='some float')
parser_tool0.add_argument('-i' , default=10, type=int, help='some integrer')
parser_tool0.add_argument('-b' , default=False, help='boolean')
parser_tool0.add_argument('opts',
help='Modify config options using the command-line',
default=None, nargs=argparse.REMAINDER)
args = parser.parse_args()
print(args)
So I would like to know what should be the best practices for that case.
Thanks in advance
Per the docs and this so answer subparsers are the way to go.
I need help with this issue, I want to take an argument from user input using argparse save it to a variable and print out the result
Example:
Message to send:
-t Greeting -m hello guys how are you
prints out:
greeting hello guys how are you
this is my code:
import argparse, shlex
parser = argparse.ArgumentParser()
parser.add_argument('-t', action='store', dest='title')
parser.add_argument('-m', action='store', dest='msg')
command = raw_input('message to send')
args = parser.parse_args(shlex.split(command))
title = args.title
msg = args.msg
print title, msg
when you enter, -t hi -m hello, it works fine but when you enter more then one word, it doesn't work. Why?
Usually, when you declare a command line switch via the add_argument method, python considers that only the next world/value should be stored inside the resulting variable. That is why the following works fine:
-t hello -m world
While the following:
-t greetings -m hello world
returns something like:
greetings hello
Using nargs, you can tell python how many values should be stored in the final variable.
For example, in your code if you declare your command line switches as:
parser.add_argument('-t', action='store', dest='title', nargs='*', type=str, required=True)
parser.add_argument('-m', action='store', dest='msg', nargs='*', type=str, required=True)
Python knows that all values following the -t switch should be stored in a list called title. The same goes for the -m switch and the msg variable.
Here I also added the type and required arguments to indicate what type of value is expected and that both switches have to be present in the command line.
Fixing your entire script so far:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-t', action='store', dest='title', nargs='*', type=str, required=True)
parser.add_argument('-m', action='store', dest='msg', nargs='*', type=str, required=True)
args = parser.parse_args()
print(" ".join(args.title), " ".join(args.msg))
All you have to do is call your script as follow:
python3 your_script.py -t greetings -m hello world
This should print:
greetings hello world
as a result.
You have 2 options here. Either quote the argument with spaces like so:
-t Hi -m "Hello word1 word2"
or
use davinellulinvega's answer. To get back the entire string with nargs='*', you'd have to:
parser.add_argument('-t', action='store', dest='title', nargs='*')
parser.add_argument('-m', action='store', dest='msg', nargs='*')
....
title = ' '.join(args.title)
msg = ' '.join(args.msg)
I am using Python argparse to take in parameters through the CLI. I have tried using the following but when I don't give any one of the arguments, it gives the output as None. I want then default ones to be the ones provided in const=. Please take a look.
parser = argparse.ArgumentParser()
parser.add_argument('--input', nargs='?', const='testInput')
parser.add_argument('--target', nargs='?', const='testTarget')
parser.add_argument('--msg', nargs='?', const='helloFromTheOtherSide')
args = parser.parse_args()
print args.input
If I don't give input, it prints it as None as I said. I want it to print TestInput instead..
Use the default argument:
parser = argparse.ArgumentParser()
parser.add_argument('--input', nargs='?', default='testInput')
parser.add_argument('--target', nargs='?', default='testTarget')
parser.add_argument('--msg', nargs='?', default='helloFromTheOtherSide')
args = parser.parse_args()
print args.input
With
parser.add_argument('--input', nargs='?', default='testInput', const='aConst')
you have a 3 way choice
prog # input='testInput'
prog --input # input='aConst'
prog --input myfile # input='myfile'
If you don't need that aConst option, omit the nargs='?'. Since it is a flagged argument it is already optional. It doesn't need the `?'.
parser.add_argument('--input', default='testInput')
I'm having some issues with getting argparse to run correctly. Previously, my script would be run as follows:
script.py <input_file(s)> <output_filename>
With code that looked like this:
cell_list_input = sys.argv[1:]
cell_list_output = sys.argv[len(cell_list_input)]
cell_list_input = cell_list_input[:len(cell_list_input)-1]
However, I'd like to add some argument parsing just to make it more readable and usable. Ideally, the format would be similar with the following options:
script.py -i <input_file(s)> -o <output_filename>
script.py --input_list <input_file(s)> --output <output_filename>
The argparse equivalent I'm trying to implement looks like this right now:
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input_list', action='append', dest='input_list', default=[], help='Input list of cell names')
parser.add_argument('-o', '--output', action='store', dest='output', help='Output file destination/name')
cli = parser.parse_args()
I know I'm doing something wrong, but can't seem to figure out what. Any help is appreciated. Thanks!
You need to specify nargs for your input file list. Try this:
parser.add_argument('-i', '--input_list', nargs="+", action='append', dest='input_list', default=[], help='Input list of cell names')
Complete example:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input_list', nargs="+", default=[], help='Input list of cell names')
parser.add_argument('-o', '--output', help='Output file destination/name')
cli = parser.parse_args()
print cli
Result:
$ python i.py -i a
Namespace(input_list=['a'], output=None)
$ python i.py -i a b c -o d
Namespace(input_list=['a', 'b', 'c'], output='d')
If the user use the optional parameter -o then the user has to use parameter -b as well.
However, the -b parameter you have to use only if the user set the parameter -o.
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-f', nargs='?', required=True)
parser.add_argument('-o', nargs='?', required=False)
parser.add_argument('-b', nargs='?', required=????)
args = parser.parse_args()
How is it possible to solve this problem?
Add a test after args = parser.parse_args():
if args.o and not args.b:
print >> sys.stderr, 'The -b option is required whenever -o is specified'
sys.exit(1)