Argparse:如果存在'x',则必需参数'y'

时间:2013-10-16 21:16:45

标签: python argparse

我的要求如下:

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

对于参数prox,我使用action ='store_true'来检查它是否存在。 我不要求任何论据。但是,如果设置了--prox,我还需要 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.')

6 个答案:

答案 0 :(得分:79)

不,argparse中没有任何选项来制作相互包含的选项集。

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

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

答案 1 :(得分:37)

你正在谈论有条件要求的论点。就像@borntyping说你可以检查错误并执行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会收到TrueFalse,具体取决于用户是否使用--prox。这也可以保证-lport-rport之间具有独立的行为。

答案 2 :(得分:5)

如果未设置lport,您是否使用prox?如果没有,为什么不提出lport的{​​{1}}和rport个参数? e.g。

prox

可以节省用户输入内容。将parser.add_argument('--prox', nargs=2, type=int, help='Prox: listen and proxy ports') 作为if args.prox is not None:进行测试同样容易。

答案 3 :(得分:5)

如果--lport存在,请使用parser.parse_known_args()方法,然后根据需要添加--rport--prox args。

# 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不会显示在帮助消息中

答案 4 :(得分:0)

接受的答案对我非常有用!由于所有代码都未经测试就被破坏了,这就是我测试接受答案的方式。 parser.error()不会引发argparse.ArgumentError错误,而是退出该过程。您必须测试SystemExit

使用pytest

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"])

灵感来自:Using unittest to test argparse - exit errors

答案 5 :(得分:0)

我是这样做的:

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