Python Argparse:如果存在“x”,则需要参数“y”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19414060/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 13:41:31  来源:igfitidea点击:

Argparse: Required argument 'y' if 'x' is present

pythonargparse

提问by asudhak

I have a requirement as follows:

我有一个要求如下:

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

for the argument prox , I use action='store_true' to check if it is present or not. I do not require any of the arguments. But, if --prox is set I requirerport and lport as well. Is there an easy way of doing this with argparse without writing custom conditional coding.

对于参数 prox ,我使用 action='store_true' 来检查它是否存在。我不需要任何论点。但是,如果设置了--prox,我也需要rport 和 lport。有没有一种简单的方法可以使用 argparse 做到这一点,而无需编写自定义条件编码。

More Code:

更多代码:

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.')

采纳答案by borntyping

No, there isn't any option in argparse to make mutually inclusivesets of options.

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

The simplest way to deal with this would be:

处理这个问题的最简单方法是:

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

回答by hpaulj

Do you use lportwhen proxis not set. If not, why not make lportand rportarguments of prox? e.g.

你用lport什么时候prox没有设置。如果不是,为什么不 makelportrportarguments of prox?例如

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

That saves your users typing. It is just as easy to test if args.prox is not None:as if args.prox:.

这可以节省您的用户输入。它就像测试if args.prox is not None:一样容易if args.prox:

回答by Mira

You're talking about having conditionally required arguments. Like @borntyping said you could check for the error and do parser.error(), or you could just apply a requirement related to --proxwhen you add a new argument.

你说的是有条件地要求参数。就像@borntyping 说的那样,您可以检查错误并执行parser.error(),或者您可以仅应用与--prox添加新参数时相关的要求。

A simple solution for your example could be:

您的示例的一个简单解决方案可能是:

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)

This way requiredreceives either Trueor Falsedepending on whether the user as used --prox. This also guarantees that -lportand -rporthave an independent behavior between each other.

这种方式required接收任一TrueFalse所使用取决于用户是否--prox。这也保证了-lport-rport彼此之间有独立的行为。

回答by Aditya Sriram

How about using parser.parse_known_args()method and then adding the --lportand --rportargs as required args if --proxis present.

如果存在,如何使用parser.parse_known_args()方法,然后将--lport--rportargs添加为所需的 args --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)

Also keep in mind that you can supply the namespace optsgenerated after the first parsing while parsing the remaining arguments the second time. That way, in the the end, after all the parsing is done, you'll have a single namespace with all the options.

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

Drawbacks:

缺点:

  • If --proxis not present the other two dependent options aren't even present in the namespace. Although based on your use-case, if --proxis not present, what happens to the other options is irrelevant.
  • Need to modify usage message as parser doesn't know full structure
  • --lportand --rportdon't show up in help message
  • 如果--prox不存在,则命名空间中甚至不存在其他两个依赖选项。尽管基于您的用例,如果--prox不存在,其他选项会发生什么是无关紧要的。
  • 需要修改使用消息,因为解析器不知道完整的结构
  • --lport并且--rport不要出现在帮助消息中

回答by Daniel Butler

The accepted answer worked great for me! Since all code is broken without tests here is how I tested the accepted answer. parser.error()does not raise an argparse.ArgumentErrorerror it instead exits the process. You have to test for SystemExit.

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

with pytest

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

with unittests

带有单元测试

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

inspired from: Using unittest to test argparse - exit errors

灵感来自:使用 unittest 测试 argparse - 退出错误