问题描述
我正在尝试向脚本添加参数依赖项.这个想法是-clone 参数将需要非空的-gituser .
I am trying to add a parameter dependency to my script. The idea is that --clone argument will require non-empty --gituser.
仔细阅读此示例后,我尝试了以下
After perusing this example, I tried the following
In [93]: class CloneAction(argparse.Action):
...: def __call__(self, parser, namespace, _):
...: if not namespace.git_user and namespace.clone:
...: parser.error('"--clone" requires legal git user')
...:
In [94]: parser = argparse.ArgumentParser()
In [95]: parser.add_argument('-g', '--gituser', dest='git_user', type=str, default='', action=CloneAction)
Out[95]: CloneAction(option_strings=['-g', '--gituser'], dest='git_user', nargs=None, const=None, default='', type=<type 'str'>, choices=None, help=None, metavar=None)
In [96]: parser.add_argument('--clone', action='store_true', default=False)
Out[96]: _StoreTrueAction(option_strings=['--clone'], dest='clone', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)
A,它没用
In [97]: parser.parse_args(['--clone'])
Out[97]: Namespace(clone=True, git_user='')
我做错了什么?
推荐答案
这种内部参数依存关系更容易在 解析之后实现.
This kind of inter argument dependency is easier to implement after parsing.
args = parser.parse_args()
if not namespace.git_user and namespace.clone:
parser.error('"--clone" requires legal git user')
到那时,git_user
和clone
都已被解析,并具有它们的最终值.
At that point, both git_user
and clone
have been parsed, and have their final values.
在实现它时,仅在有--gituser
参数时才运行自定义操作.因此,我认为在不带--clone
的情况下给它--gituser
时,它将引发错误.
As you implemented it, the custom action is run only when there's a --gituser
argument. So I think it will raise the error when you give it --gituser
without --clone
.
您可以给--clone
一个类似的自定义操作,但是它也必须处理store_true
详细信息.而--clone --gituser value
序列会发生什么? clone
操作将在解析gituser
值之前运行.这样的测试会遇到一些棘手的参数顺序问题.
You could give --clone
a similar custom action, but it would also have to handle the store_true
details. And what should happen with the --clone --gituser value
sequence? The clone
action will be run before the gituser
value has been parsed. Tests like this run into some tough argument order problems.
其他一些问题:
-
您的自定义操作不存储任何值,无论是否出错.最好自定义
store
子类.
自定义操作应引发argparse.ArgumentError
,而不是直接调用parser.error
.
custom actions should raise argparse.ArgumentError
rather than call parser.error
directly.
单元测试文件test/test_argparse.py
带有这样的相互测试的自定义操作示例.但这只是一个玩具,验证是否允许这样的代码.
The unittest file, test/test_argparse.py
has an example of custom actions with mutual tests like this. But it's just a toy, verifying that such code is allowed.
=================
==================
从理论上讲,您可以实现--clone
动作,该动作可以设置--gituser
动作的required
属性.这样,如果不使用--gituser
,则parse_args
的最终required
动作测试将引发错误.但这需要保存对out[95]
中显示的操作的引用(或在parse._actions
列表中找到该引用.可行但混乱.
You could, in theory, implement a --clone
action that sets the required
attribute of the --gituser
Action. That way, if --gituser
is not used, the final required
actions test of parse_args
will raise an error. But that requires saving a reference to the Action displayed in out[95]
(or finding that in the parse._actions
list. Feasible but messy.
==================
===================
这是来自test/test_argparse.py
的一对交互的自定义操作类的示例.
Here's an example of a pair of interacting custom action classes from test/test_argparse.py
.
class OptionalAction(argparse.Action):
def __call__(self, parser, namespace, value, option_string=None):
try:
# check destination and option string
assert self.dest == 'spam', 'dest: %s' % self.dest
assert option_string == '-s', 'flag: %s' % option_string
# when option is before argument, badger=2, and when
# option is after argument, badger=<whatever was set>
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)
# check destination
assert self.dest == 'badger', 'dest: %s' % self.dest
# when argument is before option, spam=0.25, and when
# option is after argument, spam=<whatever was set>
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)
并应与以下产品一起使用:
And supposed to work with:
'-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)),
这是可以执行的那种交叉检查的示例.但我会重复一遍,通常,交互最好在解析后而不是在解析后处理.
This is an example of the kind of cross checking that can be done. But I'll repeat that generally interactions are best handled after parsing, not during.
关于实现问题-如果用户不给您--gituser
,则永远不会调用您的自定义操作. optional
的Action.__call__
仅在使用该参数时使用.始终使用positionals
,但不使用optionals
.
As to the implementation question - if the user does not give you --gituser
, your custom Action is never called. The Action.__call__
of an optional
is only used when that argument is used. positionals
are always used, but not optionals
.
这篇关于Python中的参数依赖关系-无法使其工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!