Як зробити python argparse взаємовиключними аргументами групи без префікса?


79

Python2.7 argparse приймає лише необов’язкові аргументи (з префіксом) у взаємовиключних групах:

parser = argparse.ArgumentParser(prog='mydaemon')
action = parser.add_mutually_exclusive_group(required=True)
action.add_argument('--start', action='store_true', help='Starts %(prog)s daemon')
action.add_argument('--stop', action='store_true', help='Stops %(prog)s daemon')
action.add_argument('--restart', action='store_true', help='Restarts %(prog)s daemon')

$ mydaemon -h

usage: mydaemon [-h] (--start | --stop | --restart)

optional arguments:
  -h, --help  show this help message and exit
  --start     Starts mydaemon daemon
  --stop      Stops mydaemon daemon
  --restart   Restarts mydaemon daemon

Чи є спосіб зробити так, щоб аргументи argparse поводились як традиційний контроль демона unix:

(start | stop | restart) and not (--start | --stop | --restart) ?

Відповіді:


75

Незважаючи на всі можливості та параметри, argparseя не думаю, що ви коли-небудь отримаєте "консервований" рядок використання, схожий на те, що ви хочете.

Тим не менш, чи ви розглядали суб-парсери з моменту вашого початкового повідомлення?

Ось реалізація без голови:

import argparse

parser = argparse.ArgumentParser(prog='mydaemon')
sp = parser.add_subparsers()
sp_start = sp.add_parser('start', help='Starts %(prog)s daemon')
sp_stop = sp.add_parser('stop', help='Stops %(prog)s daemon')
sp_restart = sp.add_parser('restart', help='Restarts %(prog)s daemon')

parser.parse_args()

Запуск цього з -hопцією дає:

usage: mydaemon [-h] {start,stop,restart} ...

positional arguments:
  {start,stop,restart}
    start               Starts mydaemon daemon
    stop                Stops mydaemon daemon
    restart             Restarts mydaemon daemon

Однією з переваг цього підходу є можливість використання set_defaultsдля кожного під-аналізатора для підключення функції безпосередньо до аргументу. Я також додав "витончений" варіант для stopта restart:

import argparse

def my_stop(args):
    if args.gracefully:
        print "Let's try to stop..."
    else:
        print 'Stop, now!'

parser = argparse.ArgumentParser(prog='mydaemon')

graceful = argparse.ArgumentParser(add_help=False)
graceful.add_argument('-g', '--gracefully', action='store_true', help='tries to terminate the process gracefully')
sp = parser.add_subparsers()
sp_start = sp.add_parser('start', help='Starts %(prog)s daemon')
sp_stop = sp.add_parser('stop', parents=[graceful],
                    description='Stops the daemon if it is currently running.',
                    help='Stops %(prog)s daemon')
sp_restart = sp.add_parser('restart', parents=[graceful], help='Restarts %(prog)s daemon')

# Hook subparsers up to functions
sp_stop.set_defaults(func=my_stop)

# Uncomment when my_start() and 
# my_restart() are implemented
#
# sp_start.set_defaults(func=my_start)
# sp_restart.set_defaults(func=my_restart)

args = parser.parse_args()
args.func(args)

Показується повідомлення "довідка" для stop:

$ python mydaemon.py stop -h
usage: mydaemon stop [-h] [-g]

Stops the daemon if it is currently running.

optional arguments:
  -h, --help        show this help message and exit
  -g, --gracefully  tries to terminate the process gracefully

Зупинка "витончено":

$ python mydaemon.py stop -g
Let's try to stop...

Але ви не показуєте, як визначити, які з параметрів запуску зупинки або перезапуску були обрані. Коли я намагаюся переглянути повторення аргументів, жоден з аргументів суб-аналізатора не відображається.
Роналду Насіменто

@RonaldoNascimento Я думаю, що на ваше запитання тут відповіли docs.python.org/3/library/ ... просто прокрутіть трохи вниз і є приклад, як це вирішити за допомогоюset_defaults
OriolAbril

@RonaldoNascimento пізно, але, думаю, моя редакція відповідає на ваше запитання. set_defaults () для my_stop () завжди був там, але його легко пропустити (навіть мною). Коментар Роналду знадобився, щоб підказати мені ваше питання. І я не впевнений, що ви робите з repr (), який не показав того, що ви очікували.
Зак Янг

79

від pymotw

import argparse

parser = argparse.ArgumentParser()

group = parser.add_mutually_exclusive_group()
group.add_argument('-a', action='store_true')
group.add_argument('-b', action='store_true')

print parser.parse_args()

вихід:

$ python argparse_mutually_exclusive.py -h  
usage: argparse_mutually_exclusive.py [-h] [-a | -b]

optional arguments:  
  -h, --help  show this help message and exit  
  -a  
  -b  

$ python argparse_mutually_exclusive.py -a  
Namespace(a=True, b=False)

$ python argparse_mutually_exclusive.py -b  
Namespace(a=False, b=True)

$ python argparse_mutually_exclusive.py -a -b  
usage: argparse_mutually_exclusive.py [-h] [-a | -b]  
argparse_mutually_exclusive.py: error: argument -b: not allowed with argument -a

версія2

import argparse

parser = argparse.ArgumentParser()

subparsers = parser.add_subparsers(help='commands')

# A list command
list_parser = subparsers.add_parser('list', help='List contents')
list_parser.add_argument('dirname', action='store', help='Directory to list')

# A create command
create_parser = subparsers.add_parser('create', help='Create a directory')
create_parser.add_argument('dirname', action='store', help='New directory to create')
create_parser.add_argument('--read-only', default=False, action='store_true',
                       help='Set permissions to prevent writing to the directory',
                       )

# A delete command
delete_parser = subparsers.add_parser('delete', help='Remove a directory')
delete_parser.add_argument('dirname', action='store', help='The directory to remove')
delete_parser.add_argument('--recursive', '-r', default=False, action='store_true',
                       help='Remove the contents of the directory, too',
                       )

print parser.parse_args(['list', 'a s d', ])
>>> Namespace(dirname='a s d')
print parser.parse_args(['list', 'a s d', 'create' ])
>>> error: unrecognized arguments: create

39

Здається, ви хочете позиційний аргумент замість взаємовиключних варіантів. Ви можете використовувати "вибір", щоб обмежити можливі прийнятні варіанти.

parser = ArgumentParser()
parser.add_argument('action', choices=('start', 'stop', 'restart'))

Це створює рядок використання, який виглядає так:

usage: foo.py [-h] {start,stop,restart}

Так, я це бачив, але вибір обмежує виразність використання. Я просто шукаю спосіб позбутися префіксів.
Carlo Pires

Що ви маєте на увазі "обмежує виразність використання"? Чи може користувач запустити сценарій, не вказавши жодного з них?
Адам Вагнер,

Коли користувач видає "mydaemon -h", допомога (використання) не є настільки зрозумілою, як використання рядка довідки для кожного аргументу.
Carlo Pires

1
@AdamWagner Що робити, якщо користувач передає більше одного аргументу? напр.foo.py start stop
Сантош Кумар,

@SantoshKumar у вашому прикладі, "стоп" не є першим позиційним аргументом, тому, якщо в моєму прикладі вище визначено лише один аргумент, це призведе до помилки, оскільки він не розпізнає "стоп" (у наведеному вами прикладі). Якби ви визначили другий позиційний аргумент, тоді значення "start" було б значенням для першого, а "stop" - значенням для другого (яким би воно не було).
Адам Вагнер,

13

Спираючись на відповідь Адама ... якщо ви хочете вказати за замовчуванням, ви завжди можете зробити наступне, щоб вони могли ефективно залишити це поле порожнім.

import argparse

ActionHelp = """
    Start = Starts the daemon (default)
    Stop = Stops the daemon
    Restart = Restarts the daemon
    """
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('action', nargs = '?', choices=('start', 'stop', 'restart'),
    default = 'start', help = ActionHelp)

print parser.parse_args(''.split())
print
print parser.parse_args('-h'.split())

який надрукує:

Namespace(action='start')

usage: program.py [-h] [{start,stop,restart}]

postional arguments:
    {start,stop,restart}
                      Start = Starts the daemon (default)
                      Stop = Stops the daemon
                      Restart = Restarts the daemon

optional arguments:
    -h, --help        show this help message and exit
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.