49

I don't think this is possible, but I want to handle exceptions from argparse myself.

For example:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', help='foo help', required=True)
try:
    args = parser.parse_args()
except:
    do_something()

When I run it:

$ myapp.py
usage: myapp --foo foo
myapp: error: argument --foo is required

But I want it to fall into the exception instead.

joedborg
  • 17,651
  • 32
  • 84
  • 118
  • 2
    You're not using argparse for what it was designed for, then. What are you wanting to do? – Chris Morgan Feb 06 '13 at 11:54
  • 10
    It's not a bad thing to change the way an otherwise great library works, just to tune it to a particular project. – joedborg Feb 06 '13 at 11:59
  • 5
    Actually you can already do that. simply catch `SystemExit` and replace `sys.stderr` with some other object. – Bakuriu Feb 06 '13 at 12:01
  • @jdborg: it's not *necessarily* bad, but it often is bad. In this case, I'd like to hear what you're trying to achieve—there may well be a better approach. – Chris Morgan Feb 06 '13 at 12:05
  • 1
    Depending on what you want to do, it may be better to modify the argument itself. Is the argument to `--foo` optional? Can you define a custom action to handle it? These may be cleaner actions than overriding `argparse`'s decision to exit. – chepner Feb 06 '13 at 13:01
  • @ChrisMorgan, If this user wants a server to have a continuous command line that runs on a server (e.g; a Flask server) and he doesn't want the app to stop running after getting an error, how would you do it? – Yoni Melki Jun 26 '21 at 05:07
  • @YoniMelki: that’s a completely different question, with *nothing* in common with this question. Search further, or ask a new question if you haven’t found anything you think matches. Comments are not a suitable place for such matters. – Chris Morgan Jul 05 '21 at 08:33
  • Python 3.9 added a `exit_on_error` parameter to `ArgumentParser()`, but it does not (yet?) throw an error for a missing required option nor an unrecognized option. See https://bugs.python.org/issue41255. – user650654 Oct 26 '21 at 23:50

2 Answers2

82

You can subclass ArgumentParser and override the error method to do something different when an error occurs:

class ArgumentParserError(Exception): pass

class ThrowingArgumentParser(argparse.ArgumentParser):
    def error(self, message):
        raise ArgumentParserError(message)

parser = ThrowingArgumentParser()
parser.add_argument(...)
...
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • 1
    Thought it would be something like that. Thanks for the clear answer. – joedborg Feb 06 '13 at 12:03
  • 3
    I was hoping to avoid something like this, though I'm glad it's an option. You see, I'm trying to print out the help menu when I get an "error: too few arguments" notification; my argparse setup requires at least one argument to run successfully, but I figure it'd be polite to print out what those commands are without the user having to run the script with the "-h" parameter. Something like: `parser.set_error('too few arguments', method_to_deal_with_error)` I suppose I can always file a bug if I want this feature. Thanks! – NuclearPeon Jul 20 '13 at 00:03
27

in my case, argparse prints 'too few arguments' then quit. after reading the argparse code, I found it simply calls sys.exit() after printing some message. as sys.exit() does nothing but throws a SystemExit exception, you can just capture this exception.

so try this to see if it works for you.

    try:
        args = parser.parse_args(args)
    except SystemExit:
        .... your handler here ...
        return
Jacob CUI
  • 1,327
  • 15
  • 11
  • 1
    Yes, this option is mentioned above in Bakuriu's comment. The unittesting `test_argparse.py` file uses this approach, along with redefining `error` to create a `ErrorRaisingArgumentParser` class. – hpaulj Mar 19 '15 at 20:48
  • 3
    the error message is thrown out on stderr. Is there a way to catch it? – Raj Nov 05 '15 at 20:33
  • 1
    @Raj You can temporarily redirect stderr to another stream/file object, for example: https://stackoverflow.com/a/6796752/2128769 – umi Oct 30 '17 at 07:38