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

Kev*_*Kev 39 python argparse

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

Rob*_*wie 44

我不知道任何基于每个参数指定退出代码的机制.您可以捕获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
Run Code Online (Sandbox Code Playgroud)

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

  • +1.对于argparse的设计来说,这是一个巨大的问题 - 它决定了如何处理错误,并且无法在不修改源的情况下按照您的意愿进行操作.它确实应该具有异常层次结构并提升它们,以便您可以准确地确定发生了什么并相应地进行.IMO,一个库应该可以帮助您实现您想要的,而不是指示代码的行为方式. (36认同)
  • @blair-写了我同意的源代码。我问这个问题是因为我以为我错过了一些神奇的独角兽财产,让我可以控制:) (2认同)
  • 之前显然也提出过类似的担忧.见http://www.python.org/dev/peps/pep-0389/#discussion-sys-stderr-and-sys-exit (2认同)
  • 不支持更好的退出方式的原因是什么?创建解析器时最好使用一个参数,例如`exit = True`。 (2认同)

Yau*_*ich 33

所有答案都很好地解释了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))
Run Code Online (Sandbox Code Playgroud)

在覆盖的情况下,主代码将继续包含简约..

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


Gre*_*ins 32

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

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

适合我,即使是在互动环节.

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


she*_*ter 11

从 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)
Run Code Online (Sandbox Code Playgroud)

  • 请注意, exit_on_error 并不适用于所有情况:[bug](https://bugs.python.org/issue41255)。至少有 2 个补丁可以解决该问题([PR1](https://github.com/python/cpython/pull/30832) 和 [PR2](https://github.com/python/cpython/pull/ 27295)),但尚未被接受。 (3认同)