Python: анализатор аргументов, который правильно обрабатывает глобальные опции для подкоманд
argparse не работает с подкомандами, получающими глобальные параметры:
import argparse
p = argparse.ArgumentParser()
p.add_argument('--arg', action='store_true')
s = p.add_subparsers()
s.add_parser('test')
буду иметь p.parse_args('--arg test'.split())
Работа,
но терпит неудачу на p.parse_args('test --arg'.split())
,
Кто-нибудь знает о парсере аргументов Python, который правильно обрабатывает глобальные опции для подкоманд?
5 ответов
>>> from docopt import docopt
>>> usage = """
... usage: prog.py command [--test]
... prog.py another [--test]
...
... --test Perform the test."""
>>> docopt(usage, argv='command --test')
{'--test': True,
'another': False,
'command': True}
>>> docopt(usage, argv='--test command')
{'--test': True,
'another': False,
'command': True}
Вы можете легко добавить этот аргумент для обоих анализаторов (основной анализатор и анализатор подкоманд):
import argparse
main = argparse.ArgumentParser()
subparser = main.add_subparsers().add_parser('test')
for p in [main,subparser]:
p.add_argument('--arg', action='store_true')
print main.parse_args('--arg test'.split()).arg
print main.parse_args('test --arg'.split()).arg
Редактировать: как указал @hpaulj в комментарии, есть также parents
аргумент, который вы можете передать ArgumentParser
конструктор или add_parser
метод. Вы можете перечислить в этом значении парсеры, которые являются основой для нового.
import argparse
base = argparse.ArgumentParser(add_help=False)
base.add_argument('--arg', action='store_true')
main = argparse.ArgumentParser(parents=[base])
subparser = main.add_subparsers().add_parser('test', parents=[base])
print main.parse_args('--arg test'.split()).arg
print main.parse_args('test --arg'.split()).arg
Больше примеров / документов:
Python argparse - добавить аргумент в несколько подпарсеров (я не уверен, что этот вопрос не слишком пересекается с этим)
В мире Python есть масса разборов аргументов. Вот некоторые из них, которые я видел, и все они должны быть в состоянии решить проблему, которую вы пытаетесь решить (основываясь на моем нечетком воспоминании о них, когда я играл с ними в последний раз):
- opster - я думаю, что это то, что использует ртуть, IIRC
- docopt- это новый, но использует интересный подход
- cliff- это относительно новый проект Дуга Хеллманна (член PSF, автор virtualenvwrapper, общий экстраординарный хакер) - это нечто большее, чем просто анализатор аргументов, но с самого начала он предназначен для обработки многоуровневых команд
- Клинт - еще один проект, целью которого является "разбор аргументов и многое другое", этот - Кеннет Рейтц (из Requests Fame).
Вот грязный обходной путь -
import argparse
p = argparse.ArgumentParser()
p.add_argument('--arg', action='store_true')
s = p.add_subparsers()
s.add_parser('test')
def my_parse_args(ss):
#parse the info the subparser knows about; don't issue an error on unknown stuff
namespace,leftover=p.parse_known_args(ss)
#reparse the unknown as global options and add it to the namespace.
if(leftover):
s.add_parser('null',add_help=False)
p.parse_args(leftover+['null'],namespace=namespace)
return namespace
#print my_parse_args('-h'.split()) #This works too, but causes the script to stop.
print my_parse_args('--arg test'.split())
print my_parse_args('test --arg'.split())
Это работает - и вы можете довольно легко изменить его, чтобы работать с sys.argv
(просто удалите разделенную строку "ss
"). Вы могли бы даже подкласс argparse.ArgumentParser
и заменить parse_args
метод с my_parse_args
и тогда вы никогда не узнаете разницу - хотя подклассы для замены одного метода кажутся мне излишними.
Я думаю, однако, что это немного нестандартный способ использования подпарасеров. Как правило, глобальные параметры должны предшествовать подпараперам, а не после.
Парсер имеет определенный синтаксис: command <global options> subcommand <subcommand ptions>
, вы пытаетесь передать подкоманде опцию, но вы ее не определили.