简体   繁体   中英

How to include one positional argument into argparse mutually exclusive group?

I know that does not make sense multiple positional arguments into a mutually exclusive group because you can't say who is who. But I need to include ONE positional argument into that.

What I need:

$ myprogram -h
usage: myprogram [-h] [--delete value | --update value | value]

Where positional value is the default action (kind of "--include"). ( myprogram without arguments must be valid too).

My first attempt (this doesn't works):

parser = ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('--delete', metavar='value')
group.add_argument('--update', metavar='value')
group.add_argument('value')

Is that possible?


Second attempt:

parser = ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('--delete', action='store_true')
group.add_argument('--update', action='store_true')
group.add_argument('--insert', action='store_true', default=True)
group.add_argument('value')

I'd do this a little bit differently:

parser = ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.set_defaults(mode='insert')
group.add_argument('--delete', action='store_const', dest='mode', const='delete')
group.add_argument('--update', action='store_const', dest='mode', const='update')
group.add_argument('--insert', action='store_const', dest='mode', const='insert')
parser.add_argument('value', nargs='?')
args = parser.parse_args()

If you additionally want to make program --delete (with no value option) fail, add

if args.mode != 'insert' and args.value:
    parser.error("can't {} without a value argument".format(args.mode))

Note that this will mean that program --insert (with no value ) still works. You could avoid this with a little more effort by having the default mode be None , doing the check above with args.mode is not None , and then doing if args.mode is None: args.mode = 'insert' or similar.

Your syntax is more clearly described as:

myprogram {--insert|--update|--delete} value

where --insert defaults to True and value is required.

argparse can make you feel like your desired syntax must fit its model when something like

if args.insert and (args.update or args.delete):
    parser.print_help()

is much more obvious.

Added in response to comment:

Here is pseudo-code (meaning I didn't test it) which shows how I would implement this:

parser.add_argument('--insert', action='store_true')
parser.add_argument('--update', action='store_true')
parser.add_argument('--delete', action='store_true')
parser.add_argument('value')
args = parser.parse_args(sys.argv)
if ((args.insert and args.delete) or
    (args.insert and args.update) or
    (args.update and args.delete)):
    # can't pick more than one, complain and quit 
elif not (args.update or args.delete):
    # they specified no action so assume insert
    args.insert = True

# now one and only one of insert/update/delete is
# True and args.value contains the argument

I hope that makes things more clear.

Make the positional argument optional (with '?')

parser = ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('--delete', metavar='value')
group.add_argument('--update', metavar='value')
group.add_argument('value', nargs='?')

usage is then:

usage: ipython [-h] [--delete value | --update value | value]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM