Apart from tinkering with the argparse
source, is there any way to control the exit status code should there be a problem when parse_args()
is called, for example, a missing required switch?
8 Answers
I'm not aware of any mechanism to specify an exit code on a per-argument basis. You can catch the SystemExit
exception raised on .parse_args()
but I'm not sure how you would then ascertain what specifically caused the error.
EDIT: For anyone coming to this looking for a practical solution, the following is the situation:
ArgumentError()
is raised appropriately when arg parsing fails. It is passed the argument instance and a messageArgumentError()
does not store the argument as an instance attribute, despite being passed (which would be convenient)- It is possible to re-raise the
ArgumentError
exception by subclassingArgumentParser
, overriding .error() and getting hold of the exception from sys.exc_info()
All that means the following code - whilst ugly - allows us to catch the ArgumentError exception, get hold of the offending argument and error message, and do as we see fit:
import argparse
import sys
class ArgumentParser(argparse.ArgumentParser):
def _get_action_from_name(self, name):
"""Given a name, get the Action instance registered with this parser.
If only it were made available in the ArgumentError object. It is
passed as it's first arg...
"""
container = self._actions
if name is None:
return None
for action in container:
if '/'.join(action.option_strings) == name:
return action
elif action.metavar == name:
return action
elif action.dest == name:
return action
def error(self, message):
exc = sys.exc_info()[1]
if exc:
exc.argument = self._get_action_from_name(exc.argument_name)
raise exc
super(ArgumentParser, self).error(message)
## usage:
parser = ArgumentParser()
parser.add_argument('--foo', type=int)
try:
parser.parse_args(['--foo=d'])
except argparse.ArgumentError, exc:
print exc.message, '\n', exc.argument
Not tested in any useful way. The usual don't-blame-me-if-it-breaks indemnity applies.
-
61+1. This is a huge problem with the design of argparse - it decides how errors are handled and makes it impossible to do it how you want without modifying the source. It really should have a hierarchy of exceptions and raise them so you can tell exactly what happened and proceed accordingly. IMO, a library should help you achieve what you want, not dictate how your code behaves. – Blair May 09 '11 at 22:56
-
2@blair - having spelunked the source code I agree. I asked the question because I thought I'd missed some magic unicorn property that would let me have control :) – Kev May 09 '11 at 23:17
-
2Similar concerns have obviously been raised before. See http://www.python.org/dev/peps/pep-0389/#discussion-sys-stderr-and-sys-exit – Rob Cowie May 10 '11 at 13:43
-
2What was the reason for not supporting a better way for not exiting? An argument when creating the parser seems like the best, e.g. `exit=True` – Thoughtful Dragon Jan 25 '16 at 22:48
-
1In 2018, 1st comment totally off-base. Just override `def error`, it's a 2-liner ;-). – JL Peyret Jan 06 '18 at 19:07
-
1What would be helpful however is parser saving the received exception before calling `error` cause all you know there is the message string, not the original cause. – JL Peyret Jan 06 '18 at 19:14
All the answers nicely explain the details of argparse implementation.
Indeed, as proposed in PEP (and pointed by Rob Cowie) one should inherit ArgumentParser and override the behavior of error or exit methods.
In my case I just wanted to replace usage print with full help print in case of the error:
class ArgumentParser(argparse.ArgumentParser):
def error(self, message):
self.print_help(sys.stderr)
self.exit(2, '%s: error: %s\n' % (self.prog, message))
In case of override main code will continue to contain the minimalistic..
# Parse arguments.
args = parser.parse_args()
# On error this will print help and cause exit with explanation message.

- 13,635
- 8
- 60
- 67
-
1Best solution around here! No code changes necessary. Thanks! Instead of exit I raised an exception in my error function. This makes argaparse smooth. – Georg W. Feb 08 '19 at 13:53
-
I think there's an issue with argparse that's exposed by this solution. If you do this: "parser.add_argument("-f", "--filter", help="filter the results", type=str)", then "args = parser.parse_args(["-f"])", you get an exception from argparse. If you remove the error method from your subclass it works like normal. – Samuel Dec 29 '20 at 21:13
Perhaps catching the SystemExit
exception would be a simple workaround:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('foo')
try:
args = parser.parse_args()
except SystemExit:
print("do something else")
Works for me, even in an interactive session.
Edit: Looks like @Rob Cowie beat me to the switch. Like he said, this doesn't have very much diagnostic potential, unless you want get silly and try to glean info from the traceback.

- 6,714
- 2
- 27
- 22
-
1This solution is perfect for my use case because I simply wanted to change the exit code, nothing else. – vvaltchev Nov 19 '20 at 20:35
As of Python 3.9, this is no longer so painful. You can now handle this via the new argparse.ArgumentParser
exit_on_error
instantiation argument. Here is an example (slightly modified from the python docs: argparse#exit_on_error):
parser = argparse.ArgumentParser(exit_on_error=False)
parser.add_argument('--integers', type=int)
try:
parser.parse_args('--integers a'.split())
except argparse.ArgumentError:
print('Catching an argumentError')
exit(-1)

- 1,091
- 1
- 10
- 21
-
1Thanks for the answer. I'm not really doing much python these days, but I'm sure your answer will help out someone else. – Kev Jan 21 '21 at 00:15
-
1This will really help me with writing some unit tests, thanks a bunch!! – htmlboss Mar 16 '21 at 14:40
-
2Notice, that exit_on_error doesn't work for all cases: [bug](https://bugs.python.org/issue41255). There are at least 2 patchs that resolve the issue ([PR1](https://github.com/python/cpython/pull/30832) and [PR2](https://github.com/python/cpython/pull/27295)), but none of them is accepted yet. – KernelPanic Mar 11 '22 at 09:36
I needed a simple method to catch an argparse error at application start and pass the error to a wxPython form. Combining the best answers from above resulted in the following small solution:
import argparse
# sub class ArgumentParser to catch an error message and prevent application closing
class MyArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(MyArgumentParser, self).__init__(*args, **kwargs)
self.error_message = ''
def error(self, message):
self.error_message = message
def parse_args(self, *args, **kwargs):
# catch SystemExit exception to prevent closing the application
result = None
try:
result = super().parse_args(*args, **kwargs)
except SystemExit:
pass
return result
# testing -------
my_parser = MyArgumentParser()
my_parser.add_argument('arg1')
my_parser.parse_args()
# check for an error
if my_parser.error_message:
print(my_parser.error_message)
running it:
>python test.py
the following arguments are required: arg1

- 1,355
- 8
- 13
You can use one of the exiting methods: http://docs.python.org/library/argparse.html#exiting-methods. It should already handle situations where the arguments are invalid, however (assuming you have defined your arguments properly).
Using invalid arguments:
% [ $(./test_argparse.py> /dev/null 2>&1) ] || { echo error }
error # exited with status code 2

- 52,505
- 13
- 109
- 108
You'd have to tinker. Look at argparse.ArgumentParser.error
, which is what gets called internally. Or you could make the arguments non-mandatory, then check and exit outside argparse.

- 24,771
- 4
- 91
- 98
While argparse.error is a method and not a class its not possible to "try", "except" all "unrecognized arguments" errors. If you want to do so you need to override the error function from argparse:
def print_help(errmsg):
print(errmsg.split(' ')[0])
parser.error = print_help
args = parser.parse_args()
on an invalid input it will now print:
unrecognised
-
1Yes, Python lets you replace the methods of objects like this. It's handy for testing and one-off changes. Subclassing is better if you need to make this change repeatedly. – hpaulj Dec 20 '14 at 01:26