web-dev-qa-db-ja.com

Python argparse相互排他グループ

私が必要なのは:

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")

ありがとう!

74
Sean

add_mutually_exclusive_groupは、グループ全体を相互に排他的にしません。グループ内のオプションを相互に排他的にします。

探しているのは サブコマンド です。 prog [-a xxxx | [-b yyy -c zzz]]、次のようになります。

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

引数の最初のセットで呼び出すには:

prog command_1 -a xxxx

2番目の引数セットで呼び出すには:

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')

試して

>>> parser.print_help()
usage: PROG [-h] [--foo] {command_1,command_2} ...

positional arguments:
  {command_1,command_2}
                        help for subcommand
    command_1           command_1 help
    command_2           help for command_2

optional arguments:
  -h, --help            show this help message and exit
  --foo                 help for foo arg.
>>>

>>> parser.parse_args(['command_1', 'working'])
Namespace(a='working', foo=False)
>>> parser.parse_args(['command_1', 'wellness', '-b x'])
usage: PROG [-h] [--foo] {command_1,command_2} ...
PROG: error: unrecognized arguments: -b x

幸運を。

89
Jonathan

Jonathan's answer は複雑なオプションには完全に適していますが、単純なケースで機能する非常に単純なソリューションがあります。 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を呼び出すことができます。最初の2つの引数は互換性があり、最後の引数は互換性がありません。

だから今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)
_

もちろん、この小さなハックは単純な場合にのみ機能し、相互に排他的なオプションやグループが多数ある場合、すべての可能なオプションをチェックするのは悪夢になります。その場合、Jonathanが提案したようなコマンドグループにオプションを分割する必要があります。

26
Oz123

これを可能にするpythonパッチ(開発中)があります。
http://bugs.python.org/issue10984

アイデアは、相互に排他的なグループの重複を許可することです。したがって、usageは次のようになります。

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

このように2つのグループを作成できるようにargparseコードを変更するのは簡単な部分でした。 usageフォーマットコードを変更するには、カスタムHelpFormatterを記述する必要がありました。

argparseでは、アクショングループは解析に影響しません。それらはただのhelpフォーマットツールです。 helpでは、相互に排他的なグループはusage行にのみ影響します。解析時に、parserは相互に排他的なグループを使用して、潜在的な競合の辞書を構築します(abまたはcbには使用できませんaなどでは発生せず、競合が発生するとエラーが発生します。

そのargparseパッチがなければ、parse_argsによって生成されたネームスペースを自分でテストする(たとえば、abの両方にデフォルト以外の値がある場合)をテストし、独自のエラーを発生させることが最善の選択だと思います。パーサー独自のエラーメカニズムを使用することもできます。

parser.error('custom error message')
4
hpaulj