Python 中的参数依赖性 - 无法使其工作
Parameter dependencies in Python - can't make it work
我正在尝试将参数依赖项添加到我的脚本中。这个想法是 --clone 参数需要非空 --gituser.
阅读 this example 之后,我尝试了以下方法
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)
唉,没用
In [97]: parser.parse_args(['--clone'])
Out[97]: Namespace(clone=True, git_user='')
我做错了什么?
这种参数间依赖在解析后更容易实现。
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
。
unittest 文件,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:
# 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
是 shorthand 对应 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)
并且应该与:
一起工作
'-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
。
我正在尝试将参数依赖项添加到我的脚本中。这个想法是 --clone 参数需要非空 --gituser.
阅读 this example 之后,我尝试了以下方法
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)
唉,没用
In [97]: parser.parse_args(['--clone'])
Out[97]: Namespace(clone=True, git_user='')
我做错了什么?
这种参数间依赖在解析后更容易实现。
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
。
unittest 文件,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:
# 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
是 shorthand 对应 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)
并且应该与:
一起工作'-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
。