54

除了修改源代码之外,如果调用时出现问题,例如缺少必需的开关argparse,是否有任何方法可以控制退出状态代码?parse_args()

4

8 回答 8

56

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

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

  • ArgumentError()当 arg 解析失败时适当地引发。它被传递参数实例和消息
  • 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'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

未以任何有用的方式进行测试。通常的不责备我,如果它破坏赔偿适用。

于 2011-05-09T22:49:58.660 回答
50

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

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

就我而言,我只想用完整的帮助打印替换使用打印以防出现错误:

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.
于 2013-06-05T14:08:50.220 回答
40

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

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

对我有用,即使在交互式会话中也是如此。

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

于 2011-05-09T22:50:38.557 回答
15

从 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)
于 2021-01-20T19:02:01.650 回答
2

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

使用无效参数:

% [ $(./test_argparse.py> /dev/null 2>&1) ] || { echo error } 
error # exited with status code 2
于 2011-05-09T22:41:13.917 回答
2

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

于 2011-05-09T22:41:37.053 回答
1

虽然 argparse.error 是一种方法而不是一个类,但它不可能“尝试”、“排除”所有“无法识别的参数”错误。如果你想这样做,你需要覆盖 argparse 中的错误函数:

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

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

在无效输入上,它现在将打印:

unrecognised
于 2014-12-18T21:40:21.370 回答
1

我需要一个简单的方法来在应用程序启动时捕获 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
于 2019-11-27T14:27:39.863 回答