Aileron79
Aileron79

Reputation: 917

How to mutually exclude multiple arguments in Python's argparse

I've read through quite a few tutorials, questions and documentation and could not figure out how to achieve this:

prog.py [-h] [-d DEVICE -l | (-m M -s S -p P)]

When using the -l argument, prog.py reads from a device interface. When providing -m, -s and/or -p, prog.py writes to that interface. Reading and writing is not possible at the same time, so reading and writing arguments are mutually exclusive.

Once DEVICE has been specified, either -l or at least one of -m, -s or -p needs to be provided, it should also be possible to provide any combination of those three.

So far I approached this problem from various angles:

This is what I tried last:

import argparse
import sys

parser = argparse.ArgumentParser()
parser.add_argument("-d","--device",
        default="system",
        help="foo")

subparsers = parser.add_subparsers(help='foo')

read_parser = subparsers.add_parser('read', help='foo')
read_parser.add_argument("-l", "--list",
        action="store_true")

write_parser = subparsers.add_parser("write", help="bar")
write_parser.add_argument("-m","--mode",
        type=str,
        choices=["on","off","auto"],
        help="foo")
write_parser.add_argument("-s", "--season",
        type=str,
        choices=["winter","summer"],
        help="foo")
write_parser.add_argument("-p","--present",
        type=int,
        choices=[0,1],
        help="foo")
parser.parse_args()

This is not even close as with subparsers argparse expects either read or write. What I need to do is add groups that are mutually exclusive. Anyone has an idea of how to solve this?

Upvotes: 3

Views: 3586

Answers (1)

grimek
grimek

Reputation: 106

You can check on your own (with basic argparse functionalities) if correct arguments combination was passed:

parser = argparse.ArgumentParser()

parser.add_argument("-d","--device",
    default="system",
    help="foo")
parser.add_argument("-l", "--list",
    action="store_true")
parser.add_argument("-m","--mode",
    type=str,
    choices=["on","off","auto"],
    help="foo")
parser.add_argument("-s", "--season",
    type=str,
    choices=["winter","summer"],
    help="foo")
parser.add_argument("-p","--present",
    type=int,
    choices=[0,1],
    help="foo")
args = parser.parse_args()

# if user defines device but not any read/write argument raise exception
if args.device is not None and not args.list and all(arg is None for arg in (args.season, args.present, args.mode)):
    parser.error('Wrong arguments passed')

# if user defines read and write arguments at the same time raise exception
if args.list and not all(arg is None for arg in (args.season, args.present, args.mode)):
    parser.error('Wrong arguments passed')

Upvotes: 1

Related Questions