Я использовал 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
принудительный выбор хотя бы одного параметра?
ОБНОВИТЬ:
Следуя комментариям: Каким способом Pythonic параметризовать программу хотя бы с одной опцией?
-x
всегда является флагом и необязателен. Отрежьте,-
если это необходимо.process
поведение по умолчанию (без необходимости указывать какие-либо параметры) и разрешить пользователю изменить его,upload
если этот параметр установлен? Обычно параметры должны быть необязательными, отсюда и название. Обязательных параметров следует избегать (это также есть вargparse
документации).Ответы:
if not (args.process or args.upload): parser.error('No action requested, add -process or -upload')
источник
argparse
этого нет встроенной опции.args = vars(parser.parse_args()) if not any(args.values()): parser.error('No arguments provided.')
источник
vars()
, которое также полезно для передачи тщательно названных параметров конструктору с **.vars
. Я просто так делал.__dict__
и раньше чувствовал себя немым.Если не часть «или обе» (я сначала пропустил это), вы можете использовать что-то вроде этого:
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")
Хотя, вероятно, было бы лучше использовать вместо этого подкоманды .
источник
--process
OR--upload
, а не XOR. Это предотвращает одновременную установку обоих параметров.-x
и--xxx
обычно являются необязательными параметрами.Я знаю, что это старо как грязь, но способ потребовать один вариант, но запретить более одного (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 -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}
Обратите внимание, что вместо логических значений для ключей "процесс" и "загрузка" используются счетчики.
Оказывается, мы не можем предотвратить дублирование этих слов:
$ 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()
Я думаю, что когда вы добавляете аргумент с префиксами опций, nargs управляет всем парсером аргументов, а не только опцией. (То , что я имею в виду, если у вас есть
--option
флаг сnargs="+"
, то--option
флаг ожидает , по крайней мере один аргумент. Если у вас естьoption
сnargs="+"
, он ожидает , что по крайней мере один аргумент в целом.)источник
choices=['process','upload']
к этому аргументу.Для 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' и т. Д.
В итоге он запускает тест, аналогичный 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 производит то же самое. Есть ли альтернативные обозначения?использование такой группы более интуитивно, чем
phihag's
простой тест?источник
add_usage_group
на этой странице: docs.python.org/2/library/argparse.html ; не могли бы вы дать ссылку на его документацию?Лучший способ сделать это - использовать встроенный в 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 = parser.add_mutually_exclusive_group(required=True)
источник
Может, использовать суб-парсеры?
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'
вы также можете привязать функции для прямого вызова данной подкоманды (см. Документацию).источник
Это достигает цели, и это также будет отражено в автоматически сгенерированном
--help
выводе argparse , что imho то, что хотят большинство здравомыслящих программистов (также работает с необязательными аргументами):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
источник
Используйте 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()
источник