Создайте необходимую группу в argparse.ArgumentParser - PullRequest
0 голосов
/ 06 мая 2020

Мне было интересно иметь класс 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))

As seen_non_default_actions атрибут недоступен в классе, я не мог понять, как достичь этой цели.

Есть подсказка, как его обойти?

1 Ответ

0 голосов
/ 10 мая 2020

У меня есть решение, основанное на предложенном hpaulj улучшении argparse 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, я работаю над этим, используя аргументы catch через 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")
...