TheDataGuy
TheDataGuy

Reputation: 3108

python argparse - How to prevent by using a combination of arguments

In argparse, I want to prevent a particular combination of arguments. Lets see the sample code.

Sample:

import argparse

parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--firstname', dest='fn', action='store')
parser.add_argument('--lastname', dest='ln', action='store')
parser.add_argument('--fullname', dest='full', action='store')
args = parser.parse_args()

For eg: --firstname --lastname --fullname

The user can run the code in 2 days.

Way 1:

code.py --firstname myfirst --lastname mylast

Way 2:

code.py --fullname myfullname

Prevent

We should not use the combination fistname, fullname or lastname, fullname. If we use both, then it should not execute.

Can someone help me to fix this?

Upvotes: 1

Views: 1614

Answers (4)

Oran Sherf
Oran Sherf

Reputation: 39

A simple solution I've found useful if:

  • You want to prevent a combination of arguments within your subparser.
  • You want more control over the prevention by checking the arguments' values or other stuff according to your needs.

In the below example, I prevented a combination of '--horizontal left' and '--vertical up' in the 'move' subparser:

import argparse


# Custom action to prevent a combination of '--horizontal left' and '--vertical up'
class PreventUpLeftStoreAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values)
        if namespace.horizontal == 'left' and namespace.vertical == 'up':
            parser.error("invalid combination of arguments: '--horizontal left' and '--vertical up' are not allowed together")


parser = argparse.ArgumentParser(description='Main Parser')
subparsers = parser.add_subparsers()

parser_move = subparsers.add_parser('move')
parser_move.add_argument('--horizontal', action=PreventUpLeftStoreAction, choices=['left', 'right'], required=True)
parser_move.add_argument('--vertical', action=PreventUpLeftStoreAction, choices=['up', 'down'], required=True)

args = parser.parse_args()
print(args)

Upvotes: 1

Nelly Mincheva
Nelly Mincheva

Reputation: 470

Like this answer proposes (on a similar question) you can do something like the following by using subparsers for both cases:

# create the top-level parser
parser = argparse.ArgumentParser(add_help=false)
subparsers = parser.add_subparsers(help='help for subcommands')

# create the parser for the "full_name" command
full_name = subparsers.add_parser('full_name', help='full_name help')
full_name.add_argument('--fullname', dest='full', action='store')

# create the parser for the "separate_names" command
separate_names = subparsers.add_parser('separate_names', help='separate_names help')
separate_names.add_argument('--firstname', dest='fn', action='store')
separate_names.add_argument('--lastname', dest='ln', action='store')

args = parser.parse_args()

You can improve it even further by requiring both the first and last name of the user as it generally makes sense.

Upvotes: 1

Sergei Osadchuk
Sergei Osadchuk

Reputation: 54

You can split your arguments into separate commands and use subparsers, for example:

import argparse


parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

parser_clean = subparsers.add_parser('clean', description='clean build folder')
parser_clean.add_argument('--all', help='clean build folder and logs', action='store_true')

parser_deploy = subparsers.add_parser('deploy')
parser_deploy.add_argument('object')
parser_deploy.add_argument('--nc', help='no cleanup', action='store_true')

args = parser.parse_args()

Upvotes: 1

LhasaDad
LhasaDad

Reputation: 2143

Not sure that is an argparse specific behavior that is possible. But as long as those items are going to their own variables in the argparse resposes its a simple set of programming to check which ones are set and issue a message and exit.

example (assuming the result of parsing is in argsvalue):

if argsvalue.fullname and (argsvalue.firstname or argsvalue.lastname):
   print ("missuse of name options.....")

This assumes the argparse default for the vars is None (then if anything is set in them they will test to true with the logic above...

Upvotes: 2

Related Questions