首页 > 解决方案 > 在 argparse.ArgumentParser 中构建所需的组

问题描述

我想知道有一个RequiredGroup类来确保在 期间ArgumentParse.parse_known_args至少提供了一个动作。我的意思是,反对在提供论据时最多_MutuallyExclusiveGroup允许一个动作,这里的目标是一个至少一个required=True

我的想法是扩展ArgumentParser类来处理它,就像使用_MutuallyExclusiveGroup. 但是,它是使用在方法内部构造的一些变量完成的,这些变量在它之后不可用。

以下是处理所指组动作的互斥性的方法片段:

# make sure all required groups had one option present
        for group in self._mutually_exclusive_groups:
            if group.required:
                for action in group._group_actions:
                    if action in seen_non_default_actions:
                        break

                # if no actions were used, report the error
                else:
                    names = [_get_action_name(action)
                             for action in group._group_actions
                             if action.help is not SUPPRESS]
                    msg = _('one of the arguments %s is required')
                    self.error(msg % ' '.join(names))

由于seen_non_default_actions属性在课堂上不可用,我无法弄清楚如何实现这个目标。

关于如何解决它的一些线索?

标签: pythonpython-3.xparsingargumentsargparse

解决方案


我得到了一个基于建议的hpauljargparse usage_tests 改进的解决方案。

与启发式算法类似,它包括利用_ActionsContainer._registries存储一些'usage_tests'在所有ArgumentParser.parse_known_args过程之后运行的。但很明显,我并没有重写原来的方法,而是我自己创建了一个ArgumentParser子类来包装函数,检查并运行注册的usage_tests

class MyArgumentParser(ArgumentParser):
    def parse_known_args(self, args=None, namespace=None):
        namespace, argv  = super(MyArgumentParser, self).parse_known_args(args, namespace)

        for test in self._registries.get('usage_tests', {}).values():
            test(self, args or sys.argv[1:], namespace)

        return namespace, argv

    def add_required_group(self, *args, **kwargs):
        group = _RequiredGroup(self, *args, **kwargs)
        self._action_groups.append(group)
        return group

因为,这样,我仍然无法访问seen_non_default_actions变量,我正在通过捕获参数来解决它sys.argv[1:]

class _RequiredGroup(_ArgumentGroup):
    def __init__(self, container, **kwargs):
        super(_RequiredGroup, self).__init__(container, **kwargs)

        name = str(id(self)) # a unique key for this test
        self.register('usage_tests', name, self.test)

    @property
    def _option_strings(self):
        option_strings = []
        for action in self._group_actions:
            option_strings += action.option_strings
        return option_strings

    def test(self, parser, args, namespace):
        for option in self._option_strings:
            if option in args:
                break

        else:  # if no actions were used, report the error
            if self._option_strings:
                parser.error(f"one of the arguments {' '.join(self._option_strings)} is required")

推荐阅读