Search code examples
pythonpython-3.xargumentscommand-line-arguments

Raise exception if ArgumentParser encounters unknown argument


I'm using the Python (version 3.9.4) library argparse to parse a small number of option flags. For a number of reasons, I'd like to handle errors in my code rather than argparse.ArgumentParser. Namely, how an unrecognized argument is handled. For example, if I ran my-python-program --foobar, I'd like to be able to catch an exception and perform work there. This testcase disables almost all of the errors I've tried, except for an invalid argument:

import argparse
import sys

try:
  parser = argparse.ArgumentParser(add_help=False, exit_on_error=False, usage=None)
  parser.add_argument("--help", action="store_true", default=False)
  parser.add_argument("--hello", default="Hello, world!")
  args = parser.parse_args()
  print(args.help, args.hello)

except Exception as err:
  print("a problem occurred!", file=sys.stderr)
  print(f"error: {err}", file=sys.stderr)

Instead, running my-python-program --foobar gives me:

usage: my-python-program [--help] [--hello HELLO]
my-python-program: error: unrecognized arguments: --foobar

Solution

  • If you look at the Python argparse source code, you can see that it calls self.error on an error. This function (at the bottom of the file), by default, prints the error message and quits. You can override this method in a subclass to raise an error instead.

    import argparse
    import sys
    
    class MyArgumentParser(argparse.ArgumentParser):
      """An argument parser that raises an error, instead of quits"""
      def error(self, message):
        raise ValueError(message)
    
    try:
      parser = MyArgumentParser(add_help=False, exit_on_error=False, usage=None)
      parser.add_argument("--help", action="store_true", default=False)
      parser.add_argument("--hello", default="Hello, world!")
      args = parser.parse_args()
      print(args.help, args.hello)
    
    except Exception as err:
      print("a problem occurred!", file=sys.stderr)
      print(f"error: {err}", file=sys.stderr)
    

    Output:

    $ python3 test.py --foobar
    a problem occurred!
    error: unrecognized arguments: --foobar