Argparse:如果存在“x”,则需要参数“y”
- 2025-03-18 08:54:00
- admin 原创
- 47
问题描述:
我有如下要求:
./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.')
解决方案 1:
不,argparse 中没有任何选项可以创建互相包含的选项集。
处理这个问题最简单的方法是:
if args.prox and (args.lport is None or args.rport is None):
parser.error("--prox requires --lport and --rport.")
实际上已经有一个开放的 PR 和一个增强建议:
https://github.com/python/cpython/issues/55797
解决方案 2:
你说的是具有条件性必需参数。就像 @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
彼此之间具有独立的行为。
解决方案 3:
如何使用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
不会出现在帮助信息中
解决方案 4:
您是否在未设置lport
时使用。如果没有,为什么不使用和参数?例如prox
`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:
。
解决方案 5:
接受的答案对我来说非常有用!由于所有代码在没有测试的情况下都会被破坏,下面是我测试接受答案的方法。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"])
灵感来自:使用 unittest 测试 argparse - 退出错误
解决方案 6:
我这样做了:
if t or x or y:
assert t and x and y, f"args: -t, -x and -y should be given together"
扫码咨询,免费领取项目管理大礼包!