9

私はPythonを学び始めましたが、今ではの大きなメリットを学んでいargparseます。を使用してargparse、引数の2つのグループを作成しました:group_listgroup_simulate。各グループには独自の引数があります。ユーザーは、各グループで1つの引数のみを指定できます(を使用して実現parser.add_mutually_exclusive_group())。

そして今、ユーザーが一方だけではなく両方のグループから引数を指定した場合、私のターゲットは構文エラーを提示します-argparseこれとこれが指定されたかどうかを尋ねるメソッドを書くことによってではなく、の機能を使用してこれを達成したい印刷構文エラー。

import argparse
parser = argparse.ArgumentParser(
        description='this is the description',
        epilog="This is the epilog",
        argument_default=argparse.SUPPRESS  
        )

parser.add_argument('-v', '--verbose', help='verbose', action='store_true', default=False)

group_list = parser.add_mutually_exclusive_group()
group_list.add_argument('-m', help='list only modules', action='store_const', dest='list', const='modules', default='all')
group_list.add_argument('-p', help='list only ports', action='store_const', dest='list', const='ports', default='all')
group_list.add_argument('--list', help='list only module or ports', choices=['modules','ports'], metavar='<modules/ports>', default='all')

group_simulate = parser.add_mutually_exclusive_group()
group_simulate.add_argument('-M', help='simulate module down', nargs=1, metavar='module_name', dest='simulate')
group_simulate.add_argument('-P', help='simulate FC port down', nargs=1, metavar='fc_port_name', dest='simulate')
group_simulate.add_argument('-I', help='simulate iSCSI port down', nargs=1, metavar='iSCSI_port_name', dest='simulate')
group_simulate.add_argument('--simulate', help='simulate module or port down', nargs=1, dest='simulate')

args = parser.parse_args()

print args

つまり、より具体的に話す:

許可された:

test.py
output: Namespace(list='all', verbose=False)
test.py -m
output: Namespace(list='modules', verbose=False)
test.py -P asfasf
output: Namespace(P=['asfasf'], list='all', verbose=False)

禁止されている:

test.py -m -P asfsaf
expected output: <the help message>
test.py -P asfasf -m
expected output: <the help message>

add_subparsersfromのオプションを使用して目的の目標を達成しようとしましたargparseが、成功しませんでした。

だから私の質問は、この状況をどのように達成するかです。

4

3 に答える 3

9

2つのサブグループの「ルート」として、共通の相互に排他的なグループを使用できます。

import argparse
parser = argparse.ArgumentParser(
        description='this is the description',
        epilog="This is the epilog",
        argument_default=argparse.SUPPRESS  
        )

parser.add_argument('-v', '--verbose', help='verbose', action='store_true', default=False)

root_group = parser.add_mutually_exclusive_group()

group_list = root_group.add_mutually_exclusive_group()
group_list.add_argument('-m', help='list only modules', action='store_const', dest='list', const='modules', default='all')
group_list.add_argument('-p', help='list only ports', action='store_const', dest='list', const='ports', default='all')
group_list.add_argument('--list', help='list only module or ports', choices=['modules','ports'], metavar='<modules/ports>', default='all')

group_simulate = root_group.add_mutually_exclusive_group()
group_simulate.add_argument('-M', help='simulate module down', nargs=1, metavar='module_name', dest='simulate')
group_simulate.add_argument('-P', help='simulate FC port down', nargs=1, metavar='fc_port_name', dest='simulate')
group_simulate.add_argument('-I', help='simulate iSCSI port down', nargs=1, metavar='iSCSI_port_name', dest='simulate')
group_simulate.add_argument('--simulate', help='simulate module or port down', nargs=1, dest='simulate')

args = parser.parse_args()

print args

結果:

$ python test.py -m -P asfafs
usage: test.py [-h] [-v] [[-m | -p | --list <modules/ports>]
                [-M module_name | -P fc_port_name | -I iSCSI_port_name | --simulate SIMULATE]
test.py: error: argument -P: not allowed with argument -m 

$ python test.py -m -p
usage: test.py [-h] [-v] [[-m | -p | --list <modules/ports>]
                [-M module_name | -P fc_port_name | -I iSCSI_port_name | --simulate SIMULATE]
test.py: error: argument -p: not allowed with argument -m
于 2013-02-02T10:40:59.370 に答える
1

Docoptを使用してください!使用法のドキュメントを作成してから、argparseを取得して作成する方法を理解するために何時間も費やす必要はありません。POSIXを知っているなら、それが標準であるため、使用法ドキュメントを解釈する方法を知っています。Docoptは、使用法のドキュメントをあなたと同じように解釈する方法を知っています。抽象化レイヤーは必要ありません。

OPは、私が彼らのヘルプテキストで読んだ内容に基づいて、彼ら自身の意図を説明できなかったと思います。私は彼らが何をしようとしているのかを推測しようとしています。


test.py

"""
usage: test.py [-h | --version]
       test.py [-v] (-m | -p)
       test.py [-v] --list (modules | ports)
       test.py [-v] (-M <module_name> | -P <fc_port_name> | -I <iSCSI_port_name>)

this is the description

optional arguments:
  -h, --help                show this help message and exit
  -v, --verbose             verbose
  -m                        list only modules (same as --list modules)
  -p                        list only ports   (same as --list ports)
  --list                    list only module or ports
  -M module_name            simulate module down
  -P fc_port_name           simulate FC port down
  -I iSCSI_port_name        simulate iSCSI port down

This is the epilog
"""

from pprint import pprint
from docopt import docopt

def cli():
    arguments = docopt(__doc__, version='Super Tool 0.2')
    pprint(arguments)

if __name__ == '__main__':
    cli()

複雑なネストされた条件を使用して、すべての使用法を1行で伝達することは可能ですが、これはより読みやすくなります。これが、docoptが非常に理にかなっている理由です。CLIプログラムの場合、ユーザーと明確に通信できるようにする必要があります。ユーザーへのコミュニケーションを作成するように説得できることを期待して、なぜいくつかのあいまいなモジュール構文を学ぶのですか?時間をかけて、ニーズやコピーパスタと同様のオプションルールを備えた他のPOSIXツールを確認してください。

于 2016-05-12T05:58:04.110 に答える
0

このパーサーのより単純なバージョンは

parser=argparse.ArgumentParser(description="this is the description",
                epilog='this is the epilog')
parser.add_argument('-v', '--vebose', action='count')
g1=parser.add_mutually_exclusive_group()
g1.add_argument('--list', help='list module or ports (default=%(default)s)', choices=['modules','ports','all'], default='all')
g1.add_argument('--simulate', '-M','-P','-C', help='simulate [module down/ FS port down/ iSCSI port down]', dest='simulate', metavar='module/port')

次のようなヘルプがあります。

usage: stack14660876.py [-h] [-v]
                        [--list {modules,ports,all} | --simulate module/port]

this is the description

optional arguments:
  -h, --help            show this help message and exit
  -v, --vebose
  --list {modules,ports,all}
                        list module or ports (default=all)
  --simulate module/port, -M module/port, -P module/port, -C module/port
                        simulate [module down/ FS port down/ iSCSI port down]

this is the epilog

verbose(ここではaに置き換えましたcount)OPセットの横にある属性、listおよびsimulatelistデフォルト値は、で、またはallに設定できます。 とは単なるショートカットであり、実際には定義に追加されません。ショートカットは、多くのオプションを定義する場合、特にオプションを一緒に使用できる場合に便利です(例)。ただし、ここでは1つのオプションのみが許可されています(以外)。modulesports-m-p-vpm-v

simulate制約のない文字列を取ります。M/P/Cオプションは単なるドキュメントの便宜であり、値を制約したり、意味を追加したりするものではありません。

これは、(または他のパーサー)の境界を押し上げるための優れた演習ですが、argparse複雑すぎて役に立たないと思います。すべてのグループ化にもかかわらず、1つのオプションのみを許可することになります。

==========================

引数の処理に関するコメントによりdocoptPOSIXC引数ライブラリを調べるようになりました。 getopt古い標準です。Pythonには、同等の機能があります。https://docs.python.org/2/library/getopt.html

GNUライブラリの他のパーサーはですargp

http://www.gnu.org/software/libc/manual/html_node/Argp.html

getoptそれが構文に何を追加するかについての明確な説明はまだ見ていません。しかし、次の段落は興味深いものです。

Argpは、いくつかの独立して定義されたオプションパーサーを1つにマージする機能も提供し、それらの間の競合を仲介して、結果をシームレスに表示します。ライブラリは、ユーザープログラムが独自のオプションパーサーと組み合わせて使用​​する可能性のあるargpオプションパーサーをエクスポートできるため、ユーザープログラムの作業が少なくなります。一部のプログラムは、ライブラリによってエクスポートされた引数パーサーのみを使用する場合があります。これにより、ライブラリによって実装された抽象化に対して一貫性のある効率的なオプション解析が実現されます。

argparseサブパーサーメカニズムに少し似ています。つまり、アクションを1つ(または複数)のサブパーサーに委任できる、ある種のメタパーサーがあります。ただし、argparseサブパーサーでは、ユーザーが明示的に名前を付ける必要があります。

可能な拡張は、メタパーサーにコンテキストを見てもらうことです。たとえば、OPの場合、[-list、-p、-m]のいずれかが見つかった場合はサブパーサーを使用し、引数listのいずれかが見つかった場合はサブパーサーを使用します。それはいくつかのより強力なグループ化ツールを与えるかもしれません。そして、そのようなことをストックで実装することは可能かもしれません。同じで複数の異なるものを作成して実行できます。simulatesimulateargparseparserssys.argv

于 2016-05-20T00:35:19.660 に答える