Python argparse mutual exclusive group


мне нужно:

pro [-a xxx | [-b yyy -c zzz]]

Я пробовал это, но не работает. Может кто-нибудь мне помочь?

group= parser.add_argument_group('Model 2')
group_ex = group.add_mutually_exclusive_group()
group_ex.add_argument("-a", type=str, action = "store", default = "", help="test")
group_ex_2 = group_ex.add_argument_group("option 2")
group_ex_2.add_argument("-b", type=str, action = "store", default = "", help="test")
group_ex_2.add_argument("-c", type=str, action = "store", default = "", help="test")

спасибо!

3 62

3 ответа:

add_mutually_exclusive_group не делает всю группу взаимоисключающей. Это делает опции внутри группы взаимоисключающими.

то, что вы ищете-это команды. Вместо prog [- a xxxx | [- b yyy-c zzz]] у вас будет:

prog 
  command 1 
    -a: ...
  command 2
    -b: ...
    -c: ...

для вызова с первым набором аргументов:

prog command_1 -a xxxx

для вызова со вторым набором аргументов:

prog command_2 -b yyyy -c zzzz

вы также можете установить аргументы субкоманды как позиционный.

prog command_1 xxxx

вроде как git или svn:

git commit -am
git merge develop

Пример Работающего

# create the top-level parser
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--foo', action='store_true', help='help for foo arg.')
subparsers = parser.add_subparsers(help='help for subcommand')

# create the parser for the "command_1" command
parser_a = subparsers.add_parser('command_1', help='command_1 help')
parser_a.add_argument('a', type=str, help='help for bar, positional')

# create the parser for the "command_2" command
parser_b = subparsers.add_parser('command_2', help='help for command_2')
parser_b.add_argument('-b', type=str, help='help for b')
parser_b.add_argument('-c', type=str, action='store', default='', help='test')

пока Джонатан отлично подходит для сложных вариантов, есть очень простое решение, которое будет работать для простых случаев, например, 1 вариант исключает 2 других варианта, как в

command [- a xxx | [ -b yyy | -c zzz ]] 

или даже как в исходном вопросе:

pro [-a xxx | [-b yyy -c zzz]]

вот как бы я это сделал:

parser = argparse.ArgumentParser()

# group 1 
parser.add_argument("-q", "--query", help="query", required=False)
parser.add_argument("-f", "--fields", help="field names", required=False)

# group 2 
parser.add_argument("-a", "--aggregation", help="aggregation",
                    required=False)

я использую здесь параметры, заданные оболочке командной строки для запроса mongodb. Элемент collection экземпляр может либо вызвать метод aggregate или метод find С необязательными аргументами query и fields, следовательно, вы понимаете, почему первые два аргумента совместимы, а последний-нет.

так что теперь я бегу parser.parse_args() и проверьте его содержание:

args = parser().parse_args()

print args.aggregation
if args.aggregation and (args.query or args.fields):
    print "-a and -q|-f are mutually exclusive ..."
    sys.exit(2)

конечно, этот маленький хак работает только для простых случаев, и это станет кошмаром, чтобы проверить все возможные варианты, если у вас есть много взаимоисключающих вариантов и групп. В этом случае вы должны разбить свои параметры на группы команд как и предлагал Джонатан.

есть патч python (в разработке), который позволит вам сделать это.
http://bugs.python.org/issue10984

идея состоит в том, чтобы разрешить перекрывающиеся взаимоисключающие группы. Так что usage может выглядеть так:

pro [-a xxx | -b yyy] [-a xxx | -c zzz]

изменение кода argparse, так что вы можете создать две группы, как это было легко. Изменение usage форматирование кода требуется написание пользовательского HelpFormatter.

на argparse, инициативных групп не влияет на разбор. Они просто форматирование. В help, взаимоисключающие группы влияют только на usage линии. При разборе, то parser использует взаимоисключающие группы для построения словаря потенциальных конфликтов (a не может произойти с b или c,b не может произойти с a и т. д.), а затем выдает ошибку, если возникает конфликт.

без этого патча argparse, я думаю, что ваш лучший выбор-проверить пространство имен произведено parse_args сами (например, если оба a и b имеют значения по умолчанию), и поднять свою собственную ошибку. Вы даже можете использовать собственный механизм ошибок парсера.

parser.error('custom error message')