How can I set up argparse to parse either 'diff -g file1 -r file2' or 'format file'?
Question:
I want to use argparse
to parse command line arguments for my program. The program supports two modes – diff
and format
.
When -diff
is chosen, the arguments -g <file1>
and -r <file2>
are also needed. When -format
is chosen, instead there should be a <file>
argument.
How can I set up this logic with argparse
? Should I use subparsers?
Answers:
When you have two "modes" that each needs to enforce different optional and/or positional parameters I think your best bet would be to use subparsers for each of the modes… Then you can either test the output namespace for which command was triggered or you can set default callables to trigger for each of the options:
Here is an example of what it could look like using this strategy.
import argparse
import sys
parser = argparse.ArgumentParser(sys.argv[0], prefix_chars="-")
subparsers = parser.add_subparsers(dest="cmd")
diff_parser = subparsers.add_parser("diff", help='diff help')
diff_parser.add_argument(
"-g",
metavar="<file1>",
action="store",
dest="gfile",
help="g help"
)
diff_parser.add_argument(
"-r",
metavar="<file2>",
action="store",
dest="rfile",
help="r help"
)
format_parser = subparsers.add_parser("format", help="format help")
format_parser.add_argument(
"file",
metavar="<file>",
help="file help"
)
args = parser.parse_args(sys.argv[1:])
Then if you wanted to use a conditional to check which command was triggered like this:
if args["cmd"] == "diff":
do something...
elif args["cmd"] == "format":
do something else....
Or using default callables like this:
diff_parser.set_defaults(func=my_diff_func)
format_parser.set_defaults(func=my_format_func)
args.func(args)
Just to share and record what I have finalized eventually.
There are two solutions that I tried and eventually I picked up the subparser one although I think both ways work well to suit this task:
- Using subparser
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='command')
subparsers.required = True
# subparser for diff
parser_multi = subparsers.add_parser('diff')
# add required arguments
parser_diff.add_argument(
'-f1',
'--file1',
type=str,
required=True
)
parser_diff.add_argument(
'-f2',
'--file2',
type=str,
required=True
)
# subparser for format
parser_format = subparsers.add_parser('format')
# add a required argument
parser_format.add_argument(
'-f',
'--file',
type=str,
required=True
)
args = parser.parse_args()
- Using conditional args parser
import argparse
import sys
mode_choices = ['diff', 'format']
parser = argparse.ArgumentParser()
parser.add_argument('-m',
'--mode',
choices=mode_choices,
help='Choose mode to start',
required=True)
if True in list(map(lambda x: mode_choices[0] in x, sys.argv)):
parser.add_argument('-f1',
'--file1',
type=str,
required=True)
parser.add_argument('-f2',
'--file2',
type=str,
required=True)
if True in list(map(lambda x: mode_choices[1] in x, sys.argv)):
parser.add_argument('-f',
'--file',
type=str,
required=True)
args = parser.parse_args()
I want to use argparse
to parse command line arguments for my program. The program supports two modes – diff
and format
.
When -diff
is chosen, the arguments -g <file1>
and -r <file2>
are also needed. When -format
is chosen, instead there should be a <file>
argument.
How can I set up this logic with argparse
? Should I use subparsers?
When you have two "modes" that each needs to enforce different optional and/or positional parameters I think your best bet would be to use subparsers for each of the modes… Then you can either test the output namespace for which command was triggered or you can set default callables to trigger for each of the options:
Here is an example of what it could look like using this strategy.
import argparse
import sys
parser = argparse.ArgumentParser(sys.argv[0], prefix_chars="-")
subparsers = parser.add_subparsers(dest="cmd")
diff_parser = subparsers.add_parser("diff", help='diff help')
diff_parser.add_argument(
"-g",
metavar="<file1>",
action="store",
dest="gfile",
help="g help"
)
diff_parser.add_argument(
"-r",
metavar="<file2>",
action="store",
dest="rfile",
help="r help"
)
format_parser = subparsers.add_parser("format", help="format help")
format_parser.add_argument(
"file",
metavar="<file>",
help="file help"
)
args = parser.parse_args(sys.argv[1:])
Then if you wanted to use a conditional to check which command was triggered like this:
if args["cmd"] == "diff":
do something...
elif args["cmd"] == "format":
do something else....
Or using default callables like this:
diff_parser.set_defaults(func=my_diff_func)
format_parser.set_defaults(func=my_format_func)
args.func(args)
Just to share and record what I have finalized eventually.
There are two solutions that I tried and eventually I picked up the subparser one although I think both ways work well to suit this task:
- Using subparser
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='command')
subparsers.required = True
# subparser for diff
parser_multi = subparsers.add_parser('diff')
# add required arguments
parser_diff.add_argument(
'-f1',
'--file1',
type=str,
required=True
)
parser_diff.add_argument(
'-f2',
'--file2',
type=str,
required=True
)
# subparser for format
parser_format = subparsers.add_parser('format')
# add a required argument
parser_format.add_argument(
'-f',
'--file',
type=str,
required=True
)
args = parser.parse_args()
- Using conditional args parser
import argparse
import sys
mode_choices = ['diff', 'format']
parser = argparse.ArgumentParser()
parser.add_argument('-m',
'--mode',
choices=mode_choices,
help='Choose mode to start',
required=True)
if True in list(map(lambda x: mode_choices[0] in x, sys.argv)):
parser.add_argument('-f1',
'--file1',
type=str,
required=True)
parser.add_argument('-f2',
'--file2',
type=str,
required=True)
if True in list(map(lambda x: mode_choices[1] in x, sys.argv)):
parser.add_argument('-f',
'--file',
type=str,
required=True)
args = parser.parse_args()