Есть ли способ контролировать порядок вычисления аргументов в Python argparse

#python #argparse

#python #argparse

Вопрос:

Давайте рассмотрим приведенный ниже пример. Анализатор содержит два аргумента — inputfile и verbosity. Функция Set_verbosity_level() используется для управления значением глобальной переменной уровня модуля (в моей реальной жизни переменной уровня пакета) равным 0-4. Функция CheckFile() выполняет тесты внутри входного файла (в реальной жизни в зависимости от типа). Я хотел бы печатать сообщения в CheckFile () в зависимости от детализации. Проблема в том, что argparse вызывает CheckFile() перед Set_verbosity_level(), поэтому уровень детализации в CheckFile всегда равен 0 / по умолчанию…

Итак, мой вопрос заключается в том, существует ли какое-либо решение, чтобы заставить argparse оценивать некоторые аргументы перед другими…

     import argparse

    VERBOSITY = 0


    def Set_verbosity_level():
        """Set the verbosity level.
        """

        def type_func(value):
            a_value = int(value)
            globals()['VERBOSITY'] = value
            print("Verbosity inside Set_verbosity_level(): "   str(globals()['VERBOSITY']))
            return value

        return type_func


    class CheckFile(argparse.FileType):
        """
        Check whatever in the file
        """

        def __init__(self, mode='r', **kwargs):
            super(CheckFile, self).__init__(mode, **kwargs)

        def __call__(self, string):
            # Do whatever processing/checking/transformation
            # e.g print some message according to verbosity
            print("Verbosity inside  CheckFile(): "   str(globals()['VERBOSITY']))
            return super(CheckFile, self).__call__(string)


    def make_parser():
        """The main argument parser."""
        parser = argparse.ArgumentParser(add_help=True)

        parser.add_argument("-V",
                            "--verbosity",
                            default=0,
                            type=Set_verbosity_level(),
                            help="Increase output verbosity.",
                            required=False)

        parser.add_argument('-i', '--inputfile',
                            help="Input file",
                            type=CheckFile(mode='r'),
                            required=True)

        return parser


    if __name__ == '__main__':
        myparser = make_parser()
        args = myparser.parse_args()
        print("Verbosity in Main: "   str(VERBOSITY))
  

Вызов этого скрипта дает:

 $python test.py -i test.bed -V 2
Verbosity inside  CheckFile(): 0
Verbosity inside Set_verbosity_level(): 2
Verbosity in Main: 2
  

Комментарии:

1. Он анализирует входные данные в порядке, который предоставляет ваш пользователь, и мы не можем легко изменить эту процедуру синтаксического анализа. Я думаю, что имеет больше смысла CheckFile после синтаксического анализа, когда вы знаете детализацию независимо от порядка ввода. В PY3 удобнее открывать файлы в with контексте, чего вы не можете сделать с argparse.FileType . Установка глобального значения VERBOSITY изнутри type функции является новой и, на мой взгляд, не в хорошем стиле Python.

Ответ №1:

argparse обрабатывает аргументы командной строки в том порядке, в котором они перечислены, поэтому, если вы просто измените порядок заданных параметров, он будет выводиться с требуемой подробностью:

 python test.py -V 2 -i test.bed
  

Это выводит:

 Verbosity inside Set_verbosity_level(): 2
Verbosity inside  CheckFile(): 2
  

Иначе невозможно указать argparse обрабатывать аргументы командной строки в порядке, отличном от того, как они перечислены.

Комментарии:

1. Я предполагаю, что это должен быть выбранный ответ на вопрос «Есть ли способ контролировать порядок вычисления аргументов в Python argparse». Я выберу ответ Ричарда, который выходит за рамки и предлагает решение моего конкретного ограничения. Лучшие

Ответ №2:

Я не знаю, можете ли вы принудительно прочитать переменную argparse первой, но вы можете использовать pythons, встроенные в анализатор командной строки в вашей основной функции:

 import sys

# Your classes here #

if __name__ == '__main__':
    verbosity = 0
    for i, sysarg in enumerate(sys.argv):
        if str(sysarg).strip().lower().replace('-','') in ['v', 'verbose']:
            try:
                verbosity = sys.argv[i   1]
            except IndexError:
                print("No verbosity level specified")
    # more code
  

Это не очень элегантно, и это не argparse, но это один из способов гарантировать, что вы получите детализацию в первую очередь.

Вы также могли бы обновить свой CheckFile класс, включив в него функцию проверки подробностей:

 class CheckFile(argparse.FileType):
    """
    Check whatever in the file
    """

    def __init__(self, mode='r', **kwargs):
        super(CheckFile, self).__init__(mode, **kwargs)

    def _check_verbosity(self):
        verbosity = 0
        for i, sysarg in enumerate(sys.argv):
            if str(sysarg).strip().lower().replace('-','') in ['v', 'verbose']:
                try:
                verbosity = sys.argv[i   1]
            except IndexError:
                print("No verbosity level specified")

        return verbosity

    def __call__(self, string):
        # Do whatever processing/checking/transformation
        # e.g print some message according to verbosity
        print("Verbosity inside  CheckFile(): {}".format(self._check_verbosity()))
        return super(CheckFile, self).__call__(string)
  

Опять же, я знаю, что на самом деле это не ответ на ваш вопрос argparse, но это решение вашей проблемы

Комментарии:

1. Я думаю, что второе решение должно сработать. Большое спасибо, Ричард, за помощь.