Python Argparse игнорировать другие параметры, когда используется определенный параметр - PullRequest
0 голосов
/ 22 ноября 2018

Я пишу программу на Python, для которой требуется интерфейс командной строки, который ведет себя определенным образом

Интерфейс командной строки должен принимать следующие вызовы:

my_prog test.svg foo
my_prog --font=Sans test.svg foo

(он сгенерирует svg со словом foo, написанным указанным шрифтом или шрифтом по умолчанию)

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

my_prog --list-fonts

, в котором все действительные параметры будут перечислены на --font, как определено шрифтами, доступными в системе.

Я использую argparse, и у меня есть что-то вроде этого:

parser = argparse.ArgumentParser()

parser.add_argument('output_file')
parser.add_argument('text')
parser.add_argument('--font', help='list options with --list-fonts')
parser.add_argument('--list-fonts', action='store_true')

args = parser.parse_args()

однако это не приводит к тому, что опция --list-fonts ведет себя так, как мне хотелось бы, поскольку два позиционных аргумента все еще требуются.

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

Как получить желаемое поведение с помощью argparse.

1 Ответ

0 голосов
/ 22 ноября 2018

argparse позволяет вам определять произвольные действия, которые нужно предпринять при встрече с аргументом, основываясь на ключевом аргументе action для add_argument ( см. Документы )

Вы можете определитьдействие, чтобы вывести список ваших шрифтов, а затем прервать разбор аргументов, что позволит избежать проверки других требуемых аргументов.

это может выглядеть так:

class ListFonts(argparse.Action):
    def __call__(self, parser, namespace, values, option_string):
        print("list of fonts here")
        parser.exit() # exits the program with no more arg parsing and checking

Затем вы можете добавить его в свой аргументнапример, так:

parser.add_argument('--list-fonts', nargs=0, action=ListFonts)

Примечание nargs=0 было добавлено, чтобы этот аргумент не нуждался в значении (код в вопросе достиг этого с помощью action='store_true')

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

my_prog --font Sans test.svg text --list-fonts

Это, вероятно, не проблема, так как это не типичный вариант использования, особенно еслитекст справки объясняет это поведение.

Если определение нового класса для каждой такой опции кажется слишком тяжелым, или, возможно, у вас есть несколько вариантов с таким поведениемзатем вы могли бы рассмотреть возможность использования функции, которая реализует желаемое действие для каждого аргумента, а затем иметь своего рода фабричную функцию, которая возвращает класс, который обертывает функцию.Полный пример этого показан ниже.

def list_fonts():
    print("list of fonts here")

def override(func):
    """ returns an argparse action that stops parsing and calls a function
    whenever a particular argument is encountered. The program is then exited """
    class OverrideAction(argparse.Action):
        def __call__(self, parser, namespace, values, option_string):
            func()
            parser.exit()
    return OverrideAction

parser = argparse.ArgumentParser()

parser.add_argument('output_file')
parser.add_argument('text')
parser.add_argument('--font', help='list options with --list-fonts')
parser.add_argument('--list-fonts', nargs=0, action=override(list_fonts),
    help='list the font options then stop, don\'t generate output')
args = parser.parse_args()
...