Python Argparse:必需的参数';y';如果';x';存在
我的要求如下:Python Argparse:必需的参数';y';如果';x';存在,python,argparse,Python,Argparse,我的要求如下: ./xyifier --prox --lport lport --rport rport 对于参数prox,我使用action='store\u true'检查它是否存在。 我不需要任何论据。但是,如果设置了--prox,我还需要rport和lport。有没有一种简单的方法可以在不编写自定义条件编码的情况下使用argparse实现这一点 更多代码: non_int.add_argument('--prox', action='store_true', help='Flag to
./xyifier --prox --lport lport --rport rport
对于参数prox,我使用action='store\u 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.')
不,argparse中没有任何选项可以生成相互包含的选项集 解决这一问题的最简单方法是:
if args.prox and (args.lport is None or args.rport is None):
parser.error("--prox requires --lport and --rport.")
当未设置
prox
时,是否使用lport
。如果不是,为什么不使用prox
的lport
和rport
参数?e、 g
parser.add_argument('--prox', nargs=2, type=int, help='Prox: listen and proxy ports')
这样可以节省用户的打字时间。如果args.prox不是None:,那么测试
就和测试如果args.prox:
一样简单:
您说的是有条件地需要参数。就像@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
接收True
或False
,具体取决于用户是否使用了--prox
。这也保证了-lport
和-rport
在彼此之间具有独立的行为。如果存在--prox
,则使用方法,然后添加--lport
和--rport
参数作为所需的参数
# 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
error,而是退出进程。您必须测试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"])
灵感来源:我是这样做的:
if t or x or y:
assert t and x and y, f"args: -t, -x and -y should be given together"
这就是我最后为
解析器所做的事。error
方法,这就是我要找的!你不应该用“或”吗?毕竟,如果args.prox和(args.lport为None或args.rport为None)都需要args,
而不是args.lport为None
,只需使用而不是args.lport
。我认为它有点像python。这会阻止您将--lport
或--rport
设置为0
,这可能是程序的有效输入。为了完整起见,当您的NARG大于1时,您将在解析的参数等中获得一个列表,您可以用通常的方式对其进行处理。例如,a,b=args.prox
,a=args.prox[0]
等。请注意,ArgumentParser
可用于解析除sys.argv
之外的列表中的参数,这种情况下会失败。如果使用--prox=
语法,也会失败。然后,必需='--prox'in'。连接(sys argv)
,但我想提到我的图书馆。例如,让你做这个问题想要做的事情,而不必让你自己验证一切(如接受的答案中所示),也不必依靠漏洞破解(如投票数第二高的回答中所示)。对于来到这里的任何人,另一个令人惊奇的解决方案是: