Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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')
like image 808
borges Avatar asked Apr 07 '13 01:04

borges


People also ask

How do you add arguments in Argparse?

After importing the library, argparse. ArgumentParser() initializes the parser so that you can start to add custom arguments. To add your arguments, use parser. add_argument() .

What are mutually exclusive arguments?

In logic, two mutually exclusive propositions are propositions that logically cannot be true in the same sense at the same time. To say that more than two propositions are mutually exclusive, depending on the context, means that one cannot be true if the other one is true, or at least one of them cannot be true.

What does Nargs do in Argparse?

Number of Arguments If you want your parameters to accept a list of items you can specify nargs=n for how many arguments to accept. Note, if you set nargs=1 , it will return as a list not a single value.


3 Answers

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.

like image 127
Danica Avatar answered Oct 27 '22 00:10

Danica


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.

like image 29
msw Avatar answered Oct 26 '22 23:10

msw


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]
like image 24
hpaulj Avatar answered Oct 27 '22 00:10

hpaulj