Argparse: 如果存在“ x”,则必需的参数“ y”

我有以下要求:

./xyifier --prox --lport lport --rport rport

对于参数 prox,我使用 action = ‘ store _ true’来检查它是否存在。 我不需要任何论据。但是,如果—— prox 设置为 I 要求 rport 和 lport。有没有一种简单的方法可以在不编写自定义条件代码的情况下使用 argparse 实现这一点。

更多密码:

non_int.add_argument('--prox', action='store_true', help='Flag to turn on proxy')
non_int.add_argument('--lport', type=int, help='Listen Port.')
non_int.add_argument('--rport', type=int, help='Proxy port.')
70872 次浏览

不,在 argparse 中没有任何选项可以相互创建 包容性选项集。

解决这个问题最简单的方法是:

if args.prox and (args.lport is None or args.rport is None):
parser.error("--prox requires --lport and --rport.")

实际上,已经有一个公开的公关提出了一个改进方案: Https://github.com/python/cpython/issues/55797

当没有设置 prox时,是否使用 lport。如果没有,为什么不使 lportrport参数的 prox?例如:。

parser.add_argument('--prox', nargs=2, type=int, help='Prox: listen and proxy ports')

这样可以节省用户的输入时间,因为测试 if args.prox is not None:和测试 if args.prox:一样容易。

你说的是有条件要求的论点。就像@born 说的,你可以检查错误并执行 parser.error(),或者你可以在添加新参数时应用一个与 --prox相关的需求。

对于你的例子,一个简单的解决方案可以是:

non_int.add_argument('--prox', action='store_true', help='Flag to turn on proxy')
non_int.add_argument('--lport', required='--prox' in sys.argv, type=int)
non_int.add_argument('--rport', required='--prox' in sys.argv, type=int)

这样,required根据用户是否使用 --prox接收 TrueFalse。这也保证了 -lport-rport在彼此之间有一个独立的行为。

如何使用 parser.parse_known_args()方法,然后添加 --lport--rport参数作为必需的参数,如果 --prox是存在的。

# just add --prox arg now
non_int = argparse.ArgumentParser(description="stackoverflow question",
usage="%(prog)s [-h] [--prox --lport port --rport port]")
non_int.add_argument('--prox', action='store_true',
help='Flag to turn on proxy, requires additional args lport and rport')
opts, rem_args = non_int.parse_known_args()
if opts.prox:
non_int.add_argument('--lport', required=True, type=int, help='Listen Port.')
non_int.add_argument('--rport', required=True, type=int, help='Proxy port.')
# use options and namespace from first parsing
non_int.parse_args(rem_args, namespace = opts)

还要记住,在第二次解析剩余参数时,可以提供第一次解析后生成的名称空间 opts。这样,在完成所有解析之后,您最终将拥有一个包含所有选项的单一名称空间。

缺点:

  • 如果不存在 --prox,则名称空间中甚至不存在其他两个相关选项。虽然基于您的用例,如果 --prox不存在,那么其他选项的变化是无关紧要的。
  • 需要修改使用消息,因为解析器不知道完整的结构
  • --lport--rport不显示在帮助消息中

这个被接受的答案对我很有用!因为所有的代码在没有测试的情况下都被破坏了,这里就是我如何测试这个被接受的答案的。parser.error()不引发 argparse.ArgumentError错误,而是退出进程。你必须测试 SystemExit

和派特

import pytest
from . import parse_arguments  # code that rasises parse.error()




def test_args_parsed_raises_error():
with pytest.raises(SystemExit):
parse_arguments(["argument that raises error"])

用单元测试

from unittest import TestCase
from . import parse_arguments  # code that rasises parse.error()


class TestArgs(TestCase):


def test_args_parsed_raises_error():
with self.assertRaises(SystemExit) as cm:
parse_arguments(["argument that raises error"])

灵感来自: 使用 unittest 测试 Arparse-exit 错误

我是这样做的:

if t or x or y:
assert t and x and y, f"args: -t, -x and -y should be given together"