У ArgumentParser
есть параметр exit_on_error
, но он влияет не на все варианты ошибок, в частности при незаполненных обязательных аргументах программа все равно принудительно завершается.
Я посмотрел исходники argparse
, вариант решения такой: отнаследоваться от ArgumentParser
и переопределить метод error
, чтобы он бросал исключение с сообщением об ошибке, а не вызывал exit
. Это вполне допустимый вариант, тем более что в докстроке к exit
явно упоминается переопределение этого метода:
def error(self, message):
"""error(message: string)
Prints a usage message incorporating the message to stderr and
exits.
If you override this in a subclass, it should not return -- it
should either exit or raise an exception.
"""
self.print_usage(_sys.stderr)
args = {'prog': self.prog, 'message': message}
self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
Смысл такой, что при переопределении метода он должен завершаться либо бросанием исключения, либо выходом из программы. Вот и заменим выход из программы на выбрасывание исключения.
Рабочий код:
import argparse
class MyException(Exception):
def __init__(self, message):
super().__init__(message)
class NoExitArgumentParser(argparse.ArgumentParser):
def error(self, message):
raise MyException(message)
parser = NoExitArgumentParser()
parser.add_argument("-i", "--input", help="путь к файлу", required=True)
parser.add_argument("-o", "--output", help="путь выходного файла", required=False)
parser.add_argument("-a", "--action", help="действие над файлом", required=True, choices=["r2c", "c2r"])
parser.add_argument("-q", "--quit", help="если указать, программа не укажет ошибки", required=False,
action='store_true')
try:
parser.parse_args()
except MyException as ex:
print("Catched exception")
parser.print_usage()
print(str(ex))
print("Hello")
Вывод при запуске без параметров:
Catched exception
usage: test_arparse.py [-h] -i INPUT [-o OUTPUT] -a {r2c,c2r} [-q]
the following arguments are required: -i/--input, -a/--action
Hello
Чтобы не показывать ошибки при включенном аргументе -q
, можно не выбрасывать ошибки, а сохранять их в список, но 100% работоспособность класса при таком варианте я уже не гарантирую:
import argparse
class NoExitArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.errors = []
def error(self, message):
self.errors.append(message)
parser = NoExitArgumentParser()
parser.add_argument("-i", "--input", help="путь к файлу", required=True)
parser.add_argument("-o", "--output", help="путь выходного файла", required=False)
parser.add_argument("-a", "--action", help="действие над файлом", required=True, choices=["r2c", "c2r"])
parser.add_argument("-q", "--quit", help="если указать, программа не укажет ошибки", required=False,
action='store_true')
args = parser.parse_args()
if parser.errors:
if args.quit:
pass
else:
parser.print_usage()
for error in parser.errors:
print(error)
print("Hello")