Siddharth Shukla Siddharth Shukla - 11 months ago 49
Python Question

handle errors in Python ArgumentParser

I want to manually handle the situation where

throws an error in case of a unknown value for an argument. For example:
If I have the following python file called

argp = argparse.ArgumentParser(description='example')
argp.add_argument('--compiler', choices=['default', 'clang3.4', 'clang3.5'])
args = argp.parse_args()

and I run the script with the following args
python --compiler=foo
it throws the following error:

error: argument --compiler: invalid choice: 'foo' (choose from 'default', 'clang3.4', 'clang3.5')
SystemExit: 2

What do I need to do in order to handle this behaviour myself instead of the script quitting itself? One idea is to subclass
and override
or just monkey patch the method but I was wondering if there's a better way that does not require overriding the standard library behaviour?

Answer Source

The whole point to defining choices is to make the parser complain about values that are not in the list. But there are some alternatives:

  • omit choices (include them in the help text if you want), and do your own testing after parsing. argparse doesn't have to do everything for you. It's main purpose is to figure out what your user wants.

  • redefine the parser.error method (via subclassing is best) to redirect the error from sys.exit. But you'll have to parse the error message to distinguish between this error and other ones that the parser might raise.

  • define a type function that checks for choices, and makes the default substitution.

The parsing of the '--compiler' option goes something like this:

  • grab the string argument after the --compiler flag
  • pass it through the type function. Default is lambda x:x. int converts it to integer, etc. Raise ValueError is value is bad.
  • check the returned value against the choices list (if any)
  • use the action to add the value to the Namespace (default simply stores it).

Error in any of these steps produces an ArgumentError which is trapped by the parser.error method and passed to a parser.exit method.

Since the store_action occurs after type and choices checking, a custom action won't bypass their errors.

Here's a possible type solution (not tested)

def compile_choices(astr):
   if astr in ['default', 'clang3.4', 'clang3.5']:
       return astr
       return 'default'
   # could raise ValueError('bad value') if there are some strings you don't like

argp.add_argument('--compiler', type=compile_choices)


If compile_choices takes other arguments, such as the list of choices or the default, you'll need to wrap in some why that defines those values before parsing.

An example accepting a binary string representation:

parser.add_argument('--binary', type=lambda x: int(x, base=2), help='integer in binary format', default='1010')