Подтвердить что ты не робот

Python argparse и управление/переопределение кода состояния выхода

Помимо использования метода argparse, существует ли способ управления кодом состояния выхода, если возникает проблема, когда вызывается parse_args(), например, отсутствующий требуемый коммутатор?

4b9b3361

Ответ 1

Я не знаю какого-либо механизма для указания кода выхода для каждого аргумента. Вы можете поймать исключение SystemExit, поднятое на .parse_args(), но я не уверен, как вы могли бы выяснить, что конкретно вызвало ошибку.

EDIT: Для тех, кто приступает к поиску практического решения, следующая ситуация:

  • ArgumentError() возникает должным образом, когда анализ аргументов не выполняется. Он передал экземпляр аргумента и сообщение
  • ArgumentError() не сохраняет аргумент как атрибут экземпляра, несмотря на то, что он был передан (что было бы удобно)
  • Можно повторно поднять исключение ArgumentError путем подкласса ArgumentParser, переопределяя .error() и получить исключение из sys.exc_info()

Все это означает, что следующий код - пока он уродливый - позволяет нам поймать исключение ArgumentError, получить аргумент оскорбительного аргумента и сообщение об ошибке и сделать так, как мы считаем нужным:

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 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

Не проверен каким-либо полезным способом. Применяется обычное возмещение ответственности за отказ от ответственности.

Ответ 2

Возможно, перехват исключения SystemExit будет простым обходным путем:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('foo')
try:
    args = parser.parse_args()
except SystemExit:
    print("do something else")

Работает для меня даже в интерактивном сеансе.

Изменить: Похоже, @Rob Cowie избил меня до переключателя. Как он сказал, у этого нет очень большого диагностического потенциала, если вы не хотите глупо и попытаться собрать информацию из трассы.

Ответ 3

Все ответы прекрасно объясняют детали реализации argparse.

Действительно, как было предложено в PEP (и указано Rob Cowie), следует наследовать ArgumentParser и переопределить поведение error или выйти.

В моем случае я просто хотел заменить печать использования полной копией справки в случае ошибки:

class ArgumentParser(argparse.ArgumentParser):

    def error(self, message):
        self.print_help(sys.stderr)
        self.exit(2, '%s: error: %s\n' % (self.prog, message))

В случае переопределения основной код будет продолжать содержать минималистичный.

# Parse arguments.
args = parser.parse_args()
# On error this will print help and cause exit with explanation message.

Ответ 4

Вы можете использовать один из методов: http://docs.python.org/library/argparse.html#exiting-methods. Однако он должен обрабатывать ситуации, когда аргументы недействительны (при условии, что вы правильно определили свои аргументы).

Использование недопустимых аргументов:

% [ $(./test_argparse.py> /dev/null 2>&1) ] || { echo error } 
error # exited with status code 2

Ответ 5

Тебе пришлось бы возиться. Посмотрите argparse.ArgumentParser.error, что и называется внутренним. Или вы можете сделать аргументы не обязательными, а затем проверить и выйти за пределы argparse.

Ответ 6

Хотя argparse.error - это метод, а не класс, его невозможно "попробовать", "за исключением" всех ошибок "непризнанных аргументов". Если вы хотите сделать это, вам нужно переопределить функцию ошибки из argparse:

def print_help(errmsg):
   print(errmsg.split(' ')[0])

parser.error = print_help
args = parser.parse_args()

на недействительном вводе, он теперь будет печатать:

unrecognised