Ответ 1
if not (args.process or args.upload):
parser.error('No action requested, add -process or -upload')
Я использовал argparse
для программы на Python, которая может -process
, -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
для принудительного argparse
хотя бы одного параметра?
ОБНОВИТЬ:
После комментариев: Какой Pythonic способ параметризовать программу хотя бы с одним вариантом?
if not (args.process or args.upload):
parser.error('No action requested, add -process or -upload')
args = vars(parser.parse_args())
if not any(args.values()):
parser.error('No arguments provided.')
Если не часть "или обе" (изначально я пропустил это), вы можете использовать что-то вроде этого:
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
(я проигнорирую это)Также существуют некоторые неявные требования при проживании в командной строке:
docopt
(файл managelog.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 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()
Если вы хотите, чтобы только один аргумент выбирался по командной строке, просто используйте value = True в качестве аргумента для группы
group = parser.add_mutually_exclusive_group(required=True)
Если вам требуется запустить программу python с хотя бы одним параметром, добавьте аргумент, в котором не имеет префикс опции (или по умолчанию) и установите nargs=+
(Minimum требуется один аргумент). Проблема с этим методом, который я нашел, состоит в том, что если вы не укажете аргумент, 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()
Я думаю, что при добавлении аргумента с префиксами параметров 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", "-up", "-proc -up" и т.д.
В результате выполняется тест, аналогичный fooobar.com/questions/76507/..., хотя сообщение об ошибке должно быть более четким:
usage: PROG [-h] (-p | -u)
PROG: error: some of the arguments process upload is required
Интересно:
- это параметры kind='any', required=True
достаточно ясно (принять любую из групп, требуется хотя бы один)?
используется (-p | -u)
clear? Требуемая взаимная_exclusive_group производит то же самое. Есть ли альтернативные обозначения?
использует такую группу, которая более интуитивно понятна, чем phihag's
простая проверка?
Используйте 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()
Может быть, использовать суб-парсеры?
import argparse
parser = argparse.ArgumentParser(description='Log archiver arguments.')
subparsers = parser.add_subparsers(dest='subparser_name', help='sub-command help')
parser_process = subparsers.add_parser('process', help='Process logs')
parser_upload = subparsers.add_parser('upload', help='Upload logs')
args = parser.parse_args()
print("Subparser: ", args.subparser_name)
Теперь --help
показывает:
$ python /tmp/aaa.py --help
usage: aaa.py [-h] {process,upload} ...
Log archiver arguments.
positional arguments:
{process,upload} sub-command help
process Process logs
upload Upload logs
optional arguments:
-h, --help show this help message and exit
$ python /tmp/aaa.py
usage: aaa.py [-h] {process,upload} ...
aaa.py: error: too few arguments
$ python3 /tmp/aaa.py upload
Subparser: upload
Вы также можете добавить дополнительные опции к этим подпарсерам. Также вместо использования dest='subparser_name'
вы также можете привязать функции, которые будут напрямую вызываться для данной dest='subparser_name'
(см. Документы).
Это достигает цели, и это также будет отражено в автоматически --help
выводе --help
, который является тем, чего хочет большинство здравомыслящих программистов (также работает с необязательными аргументами):
parser.add_argument(
'commands',
nargs='+', # require at least 1
choices=['process', 'upload'], # restrict the choice
help='commands to execute'
)
Официальные документы по этому вопросу: https://docs.python.org/3/library/argparse.html#choices.