I want to use argparse to build a tool with subcommand. The possible syntax could be
/tool.py download --from 1234 --interval 60
/tool.py download --build 1432
/tool.py clean --numbers 10
So I want to use argparse to implement:
But I didn't find a way to pair '--from' and '--internal' to a group, then make the group is mutual exclusive with '--build'.
Below is my current code, and it only make the '--from' and '--build' are mutual exclusive. Neither ensure '--from' and '--interval' come together, nor ensure '--interval' and '--build' are mutual exclusive.
parser = argparse.ArgumentParser(description='A Tool')
subparsers = parser.add_subparsers(help='sub-command help')
#create the parser for the 'download' command
download_parser = subparsers.add_parser('download', help='download help')
download_parser.add_argument('--interval', dest='interval', type=int,help='interval help')
group = download_parser.add_mutually_exclusive_group()
group.add_argument('--from',type=int, help='from help')
group.add_argument('--build', type=int, help='interval help')
For example,
/tool.py download --from 1234
should not be allowed because '--from' must work with '--interval'. But my code accepts it silently.
And
/tool.py download --interval 1234 --build 5678
should not be allowed because '--build' can't be used with other argument. But my code accepts it too.
Any suggestion will be highly appreciated. Thanks.
You could use custom actions for this:
import argparse
import sys
class VerifyNoBuild(argparse.Action):
def __call__(self, parser, args, values, option_string=None):
# print 'No: {n} {v} {o}'.format(n=args, v=values, o=option_string)
if args.build is not None:
parser.error(
'--build should not be used with --from or --interval')
setattr(args, self.dest, values)
class VerifyOnlyBuild(argparse.Action):
def __call__(self, parser, args, values, option_string=None):
# print 'Only: {n} {v} {o}'.format(n=args, v=values, o=option_string)
if getattr(args, 'from') is not None:
parser.error('--from should not be used with --build')
if getattr(args, 'interval') is not None:
parser.error('--interval should not be used with --build')
setattr(args, self.dest, values)
parser = argparse.ArgumentParser(description='A Tool')
subparsers = parser.add_subparsers(help='sub-command help')
# create the parser for the 'download' command
download_parser = subparsers.add_parser('download', help='download help')
download_parser.add_argument('--interval',
type=int, help='interval help',
action=VerifyNoBuild)
download_parser.add_argument('--from',
type=int, action=VerifyNoBuild)
download_parser.add_argument('--build',
type=int, action=VerifyOnlyBuild)
args = parser.parse_args('download --from 1234 --interval 60'.split())
print(args)
# Namespace(build=None, from=1234, interval=60)
args = parser.parse_args('download --build 1432'.split())
print(args)
# Namespace(build=1432, from=None, interval=None)
args = parser.parse_args('download --build 1432 --from 1234'.split())
print(args)
# usage: test.py download [-h] [--interval INTERVAL] [--from FROM] [--build BUILD]
# test.py download: error: --build should not be used with --from or --interval
args = parser.parse_args('download --build 1432 --interval 60'.split())
print(args)
# usage: test.py download [-h] [--interval INTERVAL] [--from FROM] [--build BUILD]
# test.py download: error: --build should not be used with --from or --interval
But really, I think this is shorter and simpler:
def parse_options():
parser = argparse.ArgumentParser(description='A Tool')
subparsers = parser.add_subparsers(help='sub-command help')
#create the parser for the 'download' command
download_parser = subparsers.add_parser('download', help='download help')
download_parser.add_argument('--interval', type=int, help='interval help')
download_parser.add_argument('--from', type=int)
download_parser.add_argument('--build', type=int)
opt=parser.parse_args()
from_interval=[getattr(opt,key) is not None for key in ('from','interval')]
if opt.build is not None:
if any(from_interval):
sys.exit('error!')
elif not all(from_interval):
sys.exit('error!')
return opt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With