Python argparse: сделайте хотя бы один аргумент обязательным
я использую argparse для программы Python, которая может -prepare,-upload или так:
parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('-process', action='store_true')
parser.add_argument('-upload', action='store_true')
args = parser.parse_args()
программа бессмысленна без хотя бы одного параметра. Как я могу настроить argparse чтобы заставить хотя бы один параметр должен быть выбран?
обновление:
после комментариев: каков Питонический способ параметризации программы хотя бы с одним вариантом?
9 ответов:
если нет 'или и' части (я изначально пропустил это) вы могли бы использовать что-то вроде этого:
parser = argparse.ArgumentParser(description='Log archiver arguments.') parser.add_argument('--process', action='store_const', const='process', dest='mode') parser.add_argument('--upload', action='store_const', const='upload', dest='mode') args = parser.parse_args() if not args.mode: parser.error("One of --process or --upload must be given")хотя, вероятно, было бы лучше использовать команды вместо.
Я знаю, что это старый, как грязь, но способ потребовать один вариант, но запретить более одного (XOR) выглядит так:
parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-process', action='store_true') group.add_argument('-upload', action='store_true') args = parser.parse_args() print argsвыход:
>opt.py usage: multiplot.py [-h] (-process | -upload) multiplot.py: error: one of the arguments -process -upload is required >opt.py -upload Namespace(process=False, upload=True) >opt.py -process Namespace(process=True, upload=False) >opt.py -upload -process usage: multiplot.py [-h] (-process | -upload) multiplot.py: error: argument -process: not allowed with argument -upload
Требования
- использовать
argparse(я проигнорирую это)- разрешить одно или два действия для вызова (по крайней мере, один требуется).
- попробуйте с помощью Pythonic (я бы скорее назвал его "POSIX" - like)
есть также некоторые неявные требования при жизни в командной строке:
- объясните использование пользователю таким образом, который легко понять
- параметры должны быть необязательно
- разрешить указание флагов и параметров
- разрешить совмещать с другими параметрами (например, имя файла или имена).
образец решения с помощью
docopt(filemanagelog.py):"""Manage logfiles Usage: managelog.py [options] process -- <logfile>... managelog.py [options] upload -- <logfile>... managelog.py [options] process upload -- <logfile>... managelog.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> Password Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password> """ if __name__ == "__main__": from docopt import docopt args = docopt(__doc__) print argsпопробуйте запустить его:
$ python managelog.py Usage: managelog.py [options] process -- <logfile>... managelog.py [options] upload -- <logfile>... managelog.py [options] process upload -- <logfile>... managelog.py -hпоказать помощь:
$ python managelog.py -h Manage logfiles Usage: managelog.py [options] process -- <logfile>... managelog.py [options] upload -- <logfile>... managelog.py [options] process upload -- <logfile>... managelog.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> P managelog.py [options] upload -- <logfile>... Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password>и использовать его:
$ python managelog.py -V -U user -P secret upload -- alfa.log beta.log {'--': True, '--pswd': 'secret', '--user': 'user', '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': False, 'upload': True}короткое альтернатива
short.pyможет быть еще более короткий вариант:
"""Manage logfiles Usage: short.py [options] (process|upload)... -- <logfile>... short.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> Password Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password> """ if __name__ == "__main__": from docopt import docopt args = docopt(__doc__) print argsиспользование выглядит так:
$ python short.py -V process upload -- alfa.log beta.log {'--': True, '--pswd': None, '--user': None, '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': 1, 'upload': 1}обратите внимание, что вместо логических значений для ключей "process" и "upload" есть счетчики.
оказывается, мы не можем предотвратить дублирование этих слов:
$ python short.py -V process process upload -- alfa.log beta.log {'--': True, '--pswd': None, '--user': None, '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': 2, 'upload': 1}выводы
разработка хорошего интерфейса командной строки может быть сложной задачей когда-нибудь.
есть несколько аспектов командной строки на основе программы:
- хороший дизайн команды линия
- выбор/использование правильного парсера
argparseпредложений много, но ограничивает возможные сценарии и может стать очень сложной.С
docoptвещи идут гораздо короче, сохраняя читаемость и предлагая высокую степень гибкости. Если вам удастся получить разбираемые аргументы из словаря и сделать некоторые преобразования (в целое число, открытие файлов..) вручную (или другой библиотекой под названиемschema), вы можете найтиdocoptхорошее подходит для разбора командной строки.
если требуется, чтобы программа python выполнялась хотя бы с одним параметром, добавьте аргумент не иметь префикс опции (- или -- по умолчанию) и установить
nargs=+(требуется минимум один аргумент). Проблема с этим методом, который я нашел, заключается в том, что если вы не укажете аргумент, argparse создаст ошибку "слишком мало аргументов" и не распечатает меню справки. Если вам не нужна эта функциональность, вот как это сделать в коде:import argparse parser = argparse.ArgumentParser(description='Your program description') parser.add_argument('command', nargs="+", help='describe what a command is') args = parser.parse_args()I думаю что когда вы добавляете аргумент с префиксами опций, nargs управляет всем анализатором аргументов, а не только опцией. (Я имею в виду, если у вас есть
--optionфлаг сnargs="+", потом--optionфлаг ожидает по крайней мере один аргумент. Если у вас естьoptionСnargs="+", его ожидает по крайней мере один аргумент в целом.)
для http://bugs.python.org/issue11588 я исследую способы обобщения
mutually_exclusive_groupконцепция для обработки таких случаев.С этим
argparse.py, https://github.com/hpaulj/argparse_issues/blob/nested/argparse.py Я умею писать:parser = argparse.ArgumentParser(prog='PROG', description='Log archiver arguments.') group = parser.add_usage_group(kind='any', required=True, title='possible actions (at least one is required)') group.add_argument('-p', '--process', action='store_true') group.add_argument('-u', '--upload', action='store_true') args = parser.parse_args() print(args)который производит следующее
help:usage: PROG [-h] (-p | -u) Log archiver arguments. optional arguments: -h, --help show this help message and exit possible actions (at least one is required): -p, --process -u, --uploadэто принимает такие ресурсы, как ключ '-U', 'вверх', '--труды --вверх' и т. д.
он заканчивается запуском тест похож на https://stackoverflow.com/a/6723066/901925, хотя сообщение об ошибке должно быть более четким:
usage: PROG [-h] (-p | -u) PROG: error: some of the arguments process upload is requiredинтересно:
параметры
kind='any', required=Trueдостаточно ясно (принять любой из группы; по крайней мере один требуется)?использования
(-p | -u)понятно? Требуемая mutually_exclusive_group производит то же самое. Есть ли какая-то альтернативная нотация?использует a группа, как это более интуитивно, чем
phihag'sпростой тест?
лучший способ сделать это с помощью python встроенный модуль add_mutually_exclusive_group.
parser = argparse.ArgumentParser(description='Log archiver arguments.') group = parser.add_mutually_exclusive_group() group.add_argument('-process', action='store_true') group.add_argument('-upload', action='store_true') args = parser.parse_args()Если вы хотите, чтобы только один аргумент был выбран командной строкой, просто используйте required=True в качестве аргумента для group
group = parser.add_mutually_exclusive_group(required=True)
используйте append_const для списка действий, а затем проверьте, что список заполнен:
parser.add_argument('-process', dest=actions, const="process", action='append_const') parser.add_argument('-upload', dest=actions, const="upload", action='append_const') args = parser.parse_args() if(args.actions == None): parser.error('Error: No actions requested')вы даже можете указать методы непосредственно в константах.
def upload: ... parser.add_argument('-upload', dest=actions, const=upload, action='append_const') args = parser.parse_args() if(args.actions == None): parser.error('Error: No actions requested') else: for action in args.actions: action()
Comments