这种相互依赖的参数在解析后更容易实现。
args = parser.parse_args()
if not namespace.git_user and namespace.clone:
parser.error('"--clone" requires legal git user')
此时,
git_user
和
clone
均已被解析并具有其最终值。
按照您的实现方式,只有在出现
--gituser
参数时才会运行自定义操作。 因此,我认为如果您给出
--gituser
而没有给出
--clone
,它将引发错误。
您可以为
--clone
提供类似的自定义操作,但还必须处理
store_true
细节。 那么
--clone --gituser value
序列应该发生什么? 在解析
gituser
值之前,将运行
clone
操作。 这样的测试遇到一些棘手的参数顺序问题。
还有其他几个问题:
- 您的自定义操作不存储任何值,无论有无错误。 最好自定义
store
子类。
- 自定义操作应引发
argparse.ArgumentError
而不是直接调用parser.error
。
test / test_argparse.py
单元测试文件中有一个相互测试的自定义操作示例。 但这只是一种玩具,验证了这样的代码是否允许。
您可以理论上实现一个
--clone
操作,该操作设置
--gituser
操作的
required
属性。 这样,如果未使用
--gituser
,则
parse_args
的最终
required
操作测试将引发错误。 但这需要保存对在
out [95]
中显示的操作的引用(或在
parse._actions
列表中找到该操作)。 可行但混乱。
下面是来自
test / test_argparse.py
的一对交互式自定义操作类的示例。
class OptionalAction(argparse.Action):
def __call__(self, parser, namespace, value, option_string=None):
try:
assert self.dest == 'spam', 'dest: %s' % self.dest
assert option_string == '-s', 'flag: %s' % option_string
expected_ns = NS(spam=0.25)
if value in [0.125, 0.625]:
expected_ns.badger = 2
elif value in [2.0]:
expected_ns.badger = 84
else:
raise AssertionError('value: %s' % value)
assert expected_ns == namespace, ('expected %s, got %s' %
(expected_ns, namespace))
except AssertionError:
e = sys.exc_info()[1]
raise ArgumentParserError('opt_action failed: %s' % e)
setattr(namespace, 'spam', value)
NS
是argparse.Namespace
的简写。
class PositionalAction(argparse.Action):
def __call__(self, parser, namespace, value, option_string=None):
try:
assert option_string is None, ('option_string: %s' %
option_string)
assert self.dest == 'badger', 'dest: %s' % self.dest
expected_ns = NS(badger=2)
if value in [42, 84]:
expected_ns.spam = 0.25
elif value in [1]:
expected_ns.spam = 0.625
elif value in [2]:
expected_ns.spam = 0.125
else:
raise AssertionError('value: %s' % value)
assert expected_ns == namespace, ('expected %s, got %s' %
(expected_ns, namespace))
except AssertionError:
e = sys.exc_info()[1]
raise ArgumentParserError('arg_action failed: %s' % e)
setattr(namespace, 'badger', value)
它们被用于
parser = argparse.ArgumentParser()
parser.add_argument('-s', dest='spam', action=OptionalAction,
type=float, default=0.25)
parser.add_argument('badger', action=PositionalAction,
type=int, nargs='?', default=2)
需要搭配以下内容一起使用:
'-s0.125' producing: NS(spam=0.125, badger=2)),
'42', NS(spam=0.25, badger=42)),
'-s 0.625 1', NS(spam=0.625, badger=1)),
'84 -s2', NS(spam=2.0, badger=84)),
这是一种可以进行的交叉检查的示例。 但我要重申,通常最好在解析后处理交互,而不是在解析期间处理。
至于实现问题 - 如果用户没有给出--gituser
,则永远不会调用您的自定义操作。 optional
的Action.__call__
仅在使用该参数时使用。 positionals
始终被使用,但不是optionals
。
CloneAction
实现? - Martijn Pieters--clone
操作只是_StoreTrueAction
,不会检查任何依赖项。你必须使用一个特殊的操作类型在那里来检查它,因为没有传递-g
参数来触发CloneAction
被检查。 - Martijn Pieters--clone
,提供--gituser
是否会出错? - Martijn Pieters