Python argparse subparser example

Argparse — парсим аргументы и параметры командной строки с легкостью

Начиная с версии Python 2.7, в набор стандартных библиотек была включена библиотека argparse для обработки аргументов (параметров, ключей) командной строки. Хотелось бы остановить на ней Ваше внимание.

Для начала рассмотрим, что интересного предлагает argparse.

  • анализа аргументов sys.argv;
  • конвертирования строковых аргументов в объекты Вашей программы и работа с ними;
  • форматирования и вывода информативных подсказок;
  • многого другого.
  • обладая всей полнотой действий с обычными параметрами командной строки, они не умеют обрабатывать позиционные аргументы (positional arguments). Позиционные аргументы — это аргументы, влияющие на работу программы, в зависимости от порядка, в котором они в эту программу передаются. Простейший пример — программа cp, имеющая минимум 2 таких аргумента («cp source destination»).
  • argparse дает на выходе более качественные сообщения о подсказке при минимуме затрат (в этом плане при работе с optparse часто можно наблюдать некоторую избыточность кода);
  • argparse дает возможность программисту устанавливать для себя, какие символы являются параметрами, а какие нет. В отличие от него, optparse считает опции с синтаксисом наподобии «-pf, -file, +rgb, /f и т.п. «внутренне противоречивыми» и «не поддерживается optpars’ом и никогда не будет»;
  • argparse даст Вам возможность использовать несколько значений переменных у одного аргумента командной строки (nargs);
  • argparse поддерживает субкоманды (subcommands). Это когда основной парсер отсылает к другому (субпарсеру), в зависимости от аргументов на входе.

Для начала работы с argparse необходимо задать парсер:

ap.py: import argparse parser = argparse.ArgumentParser(description='Great Description To Be Here')

Далее, парсеру стоит указать, какие объекты Вы от него ждете. В частном случае, это может выглядеть так:

parser.add_argument('-n', action='store', dest='n', help='Simple value')

Если действие (action) для данного аргумента не задано, то по умолчанию он будет сохраняться (store) в namespace, причем мы также можем указать тип этого аргумента (int, boolean и тд). Если имя возвращаемого аргумента (dest) задано, его значение будет сохранено в соответствующем атрибуте namespace.

print parser.parse_args(['-n', '3']) Namespace(n='3') print parser.parse_args([]) Namespace(n=None) print parser.parse_args(['-a', '3']) error: unrecognized arguments: -a 3

Простой пример программы, возводящей в квадрат значение позиционного аргумента (square) и формирующей вывод в зависимости от аргумента опционального (-v):

 import argparse parser = argparse.ArgumentParser() parser.add_argument("square", type=int, help="display a square of a given number") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity") args = parser.parse_args() answer = args.square**2 if args.verbose: print("the square of <> equals <>".format(args.square, answer)) else: print(answer)

Остановимся на действиях (actions). Они могут быть следующими:
— store: возвращает в пространство имен значение (после необязательного приведения типа). Как уже говорилось, store — действие по умолчанию;

Читайте также:  Индекс символа строки питон

— store_const: в основном используется для флагов. Либо вернет Вам значение, указанное в const, либо (если ничего не указано), None. Пример:

parser.add_argument('--LifetheUniverseandEverything', action='store_const', const=42) print parser.parse_args(['--LifetheUniverseandEverything']) Namespace(LifetheUniverseandEverything=42)

— store_true / store_false: аналог store_const, но для булевых True и False;

— append: возвращает список путем добавления в него значений агрументов. Пример:

parser.add_argument('--l', action='append') print parser.parse_args('--l a --l b --l Y'.split()) Namespace(l=['abY'])

— append_const: возвращение значения, определенного в спецификации аргумента, в список. Пока у меня не было кейса, в котором понадобился бы append_const.

— count: как следует из названия, считает, сколько раз встречается значение данного аргумента. Пример:

parser.add_argument('--verbose', '-v', action='count') print parser.parse_args('-vvv'.split()) Namespace(verbose=3)

В зависимости от переданного в конструктор парсера аргумента add_help (булевого типа), будет определяться, включать или не включать в стандартный вывод по ключам [‘-h’, ‘—help’] сообщения о помощи. То же самое будет иместь место с аргументом version (строкового типа), ключи по умолчанию: [‘-v’, ‘—version’]. При запросе помощи или номера версии, дальнейшее выполнение прерывается.

parser = argparse.ArgumentParser(add_help=True, version='4.0')

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

parent_parser = argparse.ArgumentParser(add_help=False) parent_parser.add_argument('--user', action="store") parent_parser.add_argument('--password', action="store") child_parser = argparse.ArgumentParser(parents=[parent_parser]) child_parser.add_argument('--show_all', action="store_true") print child_parser.parse_args(['--user', 'guest']) Namespace(password=None, show_all=False, user='guest')

Обратите внимание, что родительский парсер создается с параметром add_help=False. Это сделано потому, что каждый парсер будет честно стараться добавить свой обработчик ключа ‘-h’, чем вызовет конфликтную ситуацию. Отсюда возникает вопрос, что делать, если у вашего дочернего парсера имеются те же ключи, что и у родительского и при этом вы хотите их использовать без всяких конфликтов? Делается это простым добавлением аргумента conflict_handler:

parent_parser = argparse.ArgumentParser(add_help=False) parent_parser.add_argument('--user', action="store") parent_parser.add_argument('--password', action="store") child_parser = argparse.ArgumentParser(parents=[parent_parser], conflict_handler='resolve') child_parser.add_argument('--user', action="store", default="Guest") print child_parser.parse_args() Namespace(password=None, user='Guest')

Помимо вышеописанного подхода к обработке команд разного уровня, существует еще и альтернативный подход, позволяющий объединить обработку всех команд в одной программе, используя субпарсеры (subparsers). Лучше всего сам за себя расскажет пример:

ap.py import argparse parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(help='List of commands') # A list command list_parser = subparsers.add_parser('list', help='List contents') list_parser.add_argument('dirname', action='store', help='Directory to list') # A create command create_parser = subparsers.add_parser('create', help='Create a directory') create_parser.add_argument('dirname', action='store', help='New directory to create') create_parser.add_argument('--read-only', default=False, action='store_true', help='Set permissions to prevent writing to the directory', )

Вот что выдаст программа с ключом ‘-h’:

Читайте также:  Create object string python

positional arguments:
list of commands
list List contents
create Create a directory

optional arguments:
-h, —help show this help message and exit

В примере можно отметить следующие вещи:
1. позиционные аргументы list, create, передаваемые программе — по сути субпарсеры;
2. аргумент ‘—read-only’ субпарсера create_parser — опциональный, dir_name — необходимый для обоих субпарсеров;
3. предусмотрена справка (помощь) как для парсера, так и для каждго из субпарсеров.

Вообще, argparse — довольно мощная и легкая библиотека, предоставляющая, на мой взгляд, очень удобный интерфейс для работы с параметрами командной строки. В следующий раз постараюсь охватить такие вопросы, как файловые аргументы (для более продвинутой работы с файлами), переменные списки аргументов, группы аргументов и более подробно остановиться на типизации аргументов.
Спасибо за внимание.

Источник

amarao / blame-praise.py

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

#!/usr/bin/env python
import argparse
def main ( command_line = None ):
parser = argparse . ArgumentParser ( ‘Blame Praise app’ )
parser . add_argument (
‘—debug’ ,
action = ‘store_true’ ,
help = ‘Print debug info’
)
subparsers = parser . add_subparsers ( dest = ‘command’ )
blame = subparsers . add_parser ( ‘blame’ , help = ‘blame people’ )
blame . add_argument (
‘—dry-run’ ,
help = ‘do not blame, just pretend’ ,
action = ‘store_true’
)
blame . add_argument ( ‘name’ , nargs = ‘+’ , help = ‘name(s) to blame’ )
praise = subparsers . add_parser ( ‘praise’ , help = ‘praise someone’ )
praise . add_argument ( ‘name’ , help = ‘name of person to praise’ )
praise . add_argument (
‘reason’ ,
help = ‘what to praise for (optional)’ ,
default = «no reason» ,
nargs = ‘?’
)
args = parser . parse_args ( command_line )
if args . debug :
print ( «debug: » + str ( args ))
if args . command == ‘blame’ :
if args . dry_run :
print ( «Not for real» )
print ( «blaming » + «, » . join ( args . name ))
elif args . command == ‘praise’ :
print ( ‘praising ‘ + args . name + ‘ for ‘ + args . reason )
if __name__ == ‘__main__’ :
main ()
Читайте также:  Php get file content with curl

Источник

Оцените статью