Python 中的参数依赖性 - 无法使其工作

2023-12-24

我正在尝试向我的脚本添加参数依赖项。这个想法是--clone参数需要非空--gituser.

细读后这个例子 https://stackoverflow.com/questions/21879657/argparse-argument-dependency,我尝试了以下

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='')

我做错了什么?


这种参数间依赖更容易实现after解析。

args = parser.parse_args()
if not namespace.git_user and namespace.clone:
    parser.error('"--clone" requires legal git user')

那时,双方git_user and clone已被解析,并具有最终值。

当您实现它时,自定义操作仅在存在时运行--gituser争论。所以我认为当你给出它时它会引发错误--gituser没有--clone.

你可以给--clone类似的自定义操作,但它还必须处理store_true细节。以及应该发生什么--clone --gituser value顺序?这clone操作将在之前运行gituser值已被解析。像这样的测试会遇到一些棘手的论证顺序问题。

其他几个问题:

  • 您的自定义操作不存储任何值,无论错误如何。最好是定制一下store子类。

  • 自定义操作应该引发argparse.ArgumentError而不是打电话parser.error直接地。

单元测试文件,test/test_argparse.py有一个带有这样的相互测试的自定义操作的示例。但这只是一个玩具,验证这样的代码是否被允许。

=================

理论上,您可以实施--clone设定的动作required的属性--gituser行动。这样一来,如果--gituser没有使用,最终required动作测试parse_args会引发错误。但这需要保存对显示在中的操作的引用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是一个简写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,您的自定义操作永远不会被调用。这Action.__call__ of an optional仅当使用该参数时才使用。positionals总是被使用,但不是optionals.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 中的参数依赖性 - 无法使其工作 的相关文章

随机推荐