【问题标题】:handle errors in Python ArgumentParser处理 Python ArgumentParser 中的错误
【发布时间】:2017-01-07 00:21:00
【问题描述】:

我想手动处理parse_args() 在参数未知值的情况下引发错误的情况。例如: 如果我有以下名为script.py的python文件:

argp = argparse.ArgumentParser(description='example')
argp.add_argument('--compiler', choices=['default', 'clang3.4', 'clang3.5'])
args = argp.parse_args()

我使用以下参数运行脚本python script.py --compiler=foo 它会引发以下错误:

error: argument --compiler: invalid choice: 'foo' (choose from 'default', 'clang3.4', 'clang3.5')
SystemExit: 2

我需要做什么才能自己处理这种行为而不是脚本自行退出?一个想法是继承 argparse.ArgumentParser 并覆盖 parse_args() 或只是猴子修补该方法,但我想知道是否有更好的方法不需要覆盖标准库行为?

【问题讨论】:

  • 您想如何处理选择列表中的不同选择?
  • @M.Klugerford 没关系,但为了简化,如果某个标志与不在选择列表中的编译器值一起传递,我想说脚本应该运行假设 clang3.4 作为参数。
  • 创建一个自定义action 怎么样?
  • @FamousJameous 这看起来很有希望。将对其进行调查并在此处更新。你有好的例子可以参考吗?
  • @Siddharth,完全披露,我从未在argparse 中编写过自定义操作。我在optparse 做过类似的事情,只是从来没有argparse。这里有一个问题:stackoverflow.com/questions/8632354/… 这可能会有所帮助。

标签: python python-2.7 python-3.x argparse


【解决方案1】:

定义选择的重点是让解析器抱怨不在列表中的值。但也有一些替代方案:

  • 省略选择(如果需要,可以将它们包含在帮助文本中),并在解析后进行自己的测试。 argparse 不必为您做所有事情。它的主要目的是弄清楚你的用户想要什么。

  • 重新定义parser.error 方法(最好通过子类化)以重定向来自sys.exit 的错误。但是您必须解析错误消息以区分此错误和解析器可能引发的其他错误。

  • 定义一个type 函数来检查选择并进行默认替换。

“--compiler”选项的解析是这样的:

  • --compiler标志后面获取字符串参数
  • 通过type 函数传递它。默认为lambda x:xint 将其转换为整数等。提高 ValueError 是值不正确。
  • 对照choices 列表(如果有)检查返回值
  • 使用action 将值添加到命名空间(默认只存储它)。

任何这些步骤中的错误都会产生一个ArgumentError,它被parser.error 方法捕获并传递给parser.exit 方法。

由于store_action 出现在typechoices 检查之后,因此自定义操作不会绕过它们的错误。

这是一个可能的type 解决方案(未测试)

def compile_choices(astr):
   if astr in ['default', 'clang3.4', 'clang3.5']:
       return astr
   else:
       return 'default'
   # could raise ValueError('bad value') if there are some strings you don't like

argp.add_argument('--compiler', type=compile_choices)

==================

如果compile_choices 采用其他参数,例如选项列表或默认值,您需要在解析之前包含一些定义这些值的原因。

接受二进制字符串表示的示例:

parser.add_argument('--binary', type=lambda x: int(x, base=2),
    help='integer in binary format', default='1010')

parser.add_argument('--binary', type=functools.partial(int, base=2), default='1010')

【讨论】:

  • 如果我想将另一个参数与编译器值一起传递给 compile_choices 怎么办?
  • 使用 lambdapartial 或包装函数来提供这些参数,然后再将其提供给解析器。我添加了一个示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-19
  • 2014-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多