1

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?

TheDataGuy
  • 2,712
  • 6
  • 37
  • 89

4 Answers4

2

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...

LhasaDad
  • 1,786
  • 1
  • 12
  • 19
1

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()
1

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.

Nelly Mincheva
  • 380
  • 3
  • 8
1

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)
Oran Sherf
  • 39
  • 9