argparse 中的交叉参数验证

Cross-argument validation in argparse

我正在寻找一种 Pythonic 方式来验证参数,当它们的验证在逻辑上取决于从其他参数解析的值时。

这是一个简单的例子:

parser.add_argument(
    '--animal', 
    choices=['raccoon', 'giraffe', 'snake'], 
    default='raccoon',
)
parser.add_argument(
    '--with-shoes', 
    action='store_true',
)

在这种情况下,解析这条命令应该会导致错误:

my_script.py --animal snake --with-shoes

添加 mutually exclusive group 在这里似乎没有帮助,因为其他组合都可以:

my_script.py --animal raccoon --with-shoes
my_script.py --animal raccoon
my_script.py --animal snake
my_script.py --animal giraffe --with-shoes
my_script.py --animal giraffe

理想情况下,验证错误不应与 --animal 参数或 --with-shoes 参数相关联,因为界面无法告诉您 哪个 值需要在这里改变。每个值都有效,但不能组合使用。

我们可以通过 post 处理 args 命名空间来做到这一点,但我正在寻找一个会导致 parser.parse_args() 调用失败的解决方案,即我们实际上失败了参数解析期间,而不是之后。

解析后检查值是最简单的。您甚至可以使用 parser.error('...') 以标准 argparse 格式生成错误消息。

argparse 独立处理每个参数,并尝试以不关心顺序的方式进行处理(positionals 除外)。每个输入值都由相应的 Action 对象(其 __call__ 方法)添加到 args 命名空间。默认的 store 操作仅使用 setattr(args, dest, value)store_truesetattr(args, dest, True).

互斥组的处理方式是保持 seen_actionsset,并对照组自己的操作列表进行检查。我探索了概括这些组以允许其他逻辑操作组合。尽管变得如此复杂(尤其是在显示 usage 时),但我没有设想对值和发生率进行测试。

可以编写自定义 Action classes 来检查 co-occurrence,但这会变得更加复杂。

我们可以给 with-shoes 一个动作 class 检查 args.animal 属性的值,如果该值为 snake 则引发错误。但是如果用户先提供 with-shoes 选项呢?我们必须给 animal 一个检查 args.with_shoes 值的自定义 class,如果是 True 则引发错误,等等。所以 shoes 有了解 animalsanimals 必须了解 shoes。解析后测试可以让你把逻辑放在一个地方。

使用像 argparse 这样的解析器的一大优势是它会为您生成用法、帮助和错误消息。但是像这样的验证逻辑很难自动表达。事实上,相对简单的 mutually-exclusive 逻辑的使用格式很脆弱,很容易被破坏。

较早前尝试回答此类问题: