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 чтобы заставить хотя бы один параметр должен быть выбран?



обновление:



после комментариев: каков Питонический способ параметризации программы хотя бы с одним вариантом?

473   9  

9 ответов:

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 (я проигнорирую это)
  • разрешить одно или два действия для вызова (по крайней мере, один требуется).
  • попробуйте с помощью Pythonic (я бы скорее назвал его "POSIX" - like)

есть также некоторые неявные требования при жизни в командной строке:

  • объясните использование пользователю таким образом, который легко понять
  • параметры должны быть необязательно
  • разрешить указание флагов и параметров
  • разрешить совмещать с другими параметрами (например, имя файла или имена).

образец решения с помощью docopt (file 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 выполнялась хотя бы с одним параметром, добавьте аргумент не иметь префикс опции (- или -- по умолчанию) и установить 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

    Ничего не найдено.