#python #argparse
#python #argparse
Вопрос:
Учитывая argparse.ArgumentParser
, например
parser.py
from argparse import ArgumentParser
p = ArgumentParser()
subs = p.add_subparsers()
a = subs.add_parser('a')
a.add_argument('aa')
b = subs.add_parser('b')
b.add_argument('bb')
p.parse_args()
Теперь я могу вызвать это с помощью python parser.py -h / b -h / a -h, и каждый вызов с предоставляет мне все параметры, относящиеся к указанному вспомогательному анализатору. Суммируя их вместе, я могу получить полный список всех аргументов.
Я могу сделать это следующим образом:
from parser import p
p.print_help()
а затем начать синтаксический анализ выходных данных, что, очевидно, не очень хорошая идея.
Я могу получить доступ p._subparsers
, но это не дало мне слишком многого.
— Как сделать это правильно?
Что я в конечном итоге хочу получить: Тест pytest, где я могу протестировать все параметры, выдающие допустимый ответ, например, python parser a aa
действительно будет делать aa
Комментарии:
1. Предоставление аргумента в
p.parser_args(['arg_a', 'arg_b'])
не то, что вам нужно? Вы также пытаетесь найти, какие аргументы существуют? Вы сможете сделать:def some_test(): p.parse_args(['a', 'aa']) p.parse_args(['b', 'bb'])
Затем вы сможете либо использоватьexcept SystemExit
, либо извлекать из ArgumentParser и переопределятьerror
метод.2. Во время тестирования я не знаю аргументов, поэтому я не могу передать их
parse_args
. Я могу получить доступ только к инициализированному анализатору и продолжить свой путь оттуда3. При доступе
p
. Вы можете получить доступ к его_actions
списку. Вы можете выполнить итерацию по нему и проверить типы. если его тип_StoreAction
, вы можете получить доступ к его dest, чтобы проверить его имя. если это_SubParsersAction
— Вы можете выполнить итерацию по внутреннемуchoices
и получить его действия. Немного больно, но это сработает4. @OrY Доступ к любым атрибутам, начинающимся с
_
, по своей сути хрупок, поскольку они могут быть изменены без уведомления в будущих выпусках. Есть ли способ использовать «общедоступные» методы?5. @alaniwi Я знаю, что это опасно, но, к сожалению, нет общедоступного способа сделать это. Более безопасным способом достижения желаемого OP может быть получение из ArgumentParser и изменение add_argument и (также add_subparsers и позже add_subparser) таким образом, чтобы при каждом вызове этой функции новые аргументы сохранялись во внешнем списке.
Ответ №1:
from argparse import ArgumentParser
p = ArgumentParser()
subs = p.add_subparsers()
a = subs.add_parser('a')
aa = a.add_argument('aa')
b = subs.add_parser('b')
bb = b.add_argument('bb')
p.parse_args()
add_argument
возвращает Action
объект. На эти объекты также есть ссылки в parser._actions
списке, но вы можете собрать ссылки самостоятельно, либо по имени, либо в виде списка (или dict). add_subparsers
это вариант на add_argument
, который создает специальный подкласс Action
, который имеет add_parser
метод.
Попробуйте запустить этот код в интерактивном сеансе и посмотрите на созданные объекты. У большинства есть repr
метод, который показывает ключевые (но не все) атрибуты. Для действий это будет включать такие вещи, как dest
, nargs
, default
и т.д. Вы даже можете изменить эти атрибуты после создания. argparse
написан как обычная иерархия классов Python.
Что касается атрибутов _
и __
— они не документированы, но это не значит, что они будут изменены в любой момент. Изменения появляются в argparse
на этапе snails, при этом много внимания уделяется обратной совместимости (хотя иногда этого недостаточно). Легче изменить документацию, чем сам код, особенно такие базовые вещи, как _actions
.
Но я не совсем уверен, что вы пытаетесь сделать. Запускать unittests с argparse
несколько неудобно. Вы можете смоделировать, args = parse.parse_args(argv)
где argv
— список строк по вашему выбору. Или вы можете установить sys.argv[1:]
новый набор строк. Или вы могли бы создать новый args=argparse.Namespace(...)
объект. Попытка сгенерировать все возможные комбинации аргументов только на основе parser
настройки звучит как большая работа, особенно при использовании подпараметров.