Python argparse并控制/覆盖退出状态代码

时间:2011-05-09 22:29:20

标签: python argparse

除了修补argparse来源之外,如果在调用parse_args()时遇到问题,有没有办法控制退出状态代码,例如,缺少必需的开关?

8 个答案:

答案 0 :(得分:37)

我不知道任何基于每个参数指定退出代码的机制。您可以捕获SystemExit上引发的.parse_args()异常,但我不确定您将如何确定具体导致错误。

编辑:对于前来寻找实用解决方案的人来说,情况如下:

    当arg解析失败时,
  • ArgumentError()被适当地引发。它传递参数实例和消息
  • ArgumentError() 将参数存储为实例属性,尽管已通过(这很方便)
  • 可以通过继承ArgumentError,重写.error()并从sys.exc_info()获取异常来重新引发ArgumentParser异常

所有这些意味着以下代码 - 虽然丑陋 - 允许我们捕获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'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

没有以任何有用的方式进行测试。通常不要责怪我,如果它打破赔偿适用。

答案 1 :(得分:29)

或许捕获SystemExit异常将是一个简单的解决方法:

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

即使是在互动环节中,也适合我。

编辑:看起来@Rob Cowie打败了我。就像他说的那样,这并没有很大的诊断潜力,除非你想要愚蠢并试图从追溯中收集信息。

答案 2 :(得分:26)

所有答案都很好地解释了 argparse 实施的细节。

确实,正如PEP中提出的(并由Rob Cowie指出),应该继承 ArgumentParser 并覆盖错误退出<的行为/ strong>方法。

在我的情况下,我只是想在错误的情况下用完全帮助打印替换使用打印:

class ArgumentParser(argparse.ArgumentParser):

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

如果覆盖主代码将继续包含minimalistic ..

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

答案 3 :(得分:9)

从 Python 3.9 开始,这不再那么痛苦。您现在可以通过新的 argparse.ArgumentParser exit_on_error 实例化参数处理此问题。这是一个示例(从 python 文档稍微修改: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)

答案 4 :(得分:2)

你必须修补。查看argparse.ArgumentParser.error,这是内部调用的内容。或者你可以使参数非强制性,然后检查并退出argparse外部。

答案 5 :(得分:1)

您可以使用其中一种退出方法:http://docs.python.org/library/argparse.html#exiting-methods。它应该已经处理了参数无效的情况,但是(假设您已正确定义了参数)。

使用无效参数:

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

答案 6 :(得分:1)

虽然argparse.error是一个方法,而不是一个类,但它不可能&#34;尝试&#34;,&#34;除了&#34;所有&#34;无法识别的论点&#34;错误。如果你想这样做,你需要覆盖argparse中的错误函数:

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

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

对于无效输入,现在将打印:

unrecognised

答案 7 :(得分:0)

我需要一个简单的方法来在应用程序启动时捕获argparse错误,并将错误传递给wxPython表单。结合以上最佳答案可以得出以下解决方案:

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)

运行它:

>python test.py
the following arguments are required: arg1