web-dev-qa-db-ja.com

Python argparse:少なくとも1つの引数を必要とします

私はargparseをPythonできるプログラム-process-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()

プログラムは、少なくとも1つのパラメーターがなければ意味がありません。少なくとも1つのパラメーターを選択するようにargparseを構成するにはどうすればよいですか?

更新:

コメントに従ってください:少なくとも1つのオプションでプログラムをパラメーター化するPythonicの方法は何ですか?

78
Adam Matan
if not (args.process or args.upload):
    parser.error('No action requested, add -process or -upload')
88
phihag
args = vars(parser.parse_args())
if not any(args.values()):
    parser.error('No arguments provided.')
27
brentlance

「または両方」の部分ではない場合(最初はこれを見逃していました)、次のようなものを使用できます。

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

ただし、代わりに subcommands を使用することをお勧めします。

20
Jacek Konieczny

私はこれが汚れとして古いことを知っていますが、1つのオプションを必要とするが複数の(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  
14
Knut

要件のレビュー

  • argparseを使用します(これは無視します)
  • 1つまたは2つのアクションを呼び出すことができます(少なくとも1つが必要です)。
  • pythonicで試してください(私はむしろ「POSIX」のように呼びます)

コマンドラインで実行する場合、暗黙的な要件もいくつかあります。

  • わかりやすい方法でユーザーに使用方法を説明する
  • オプションはオプションです
  • フラグとオプションの指定を許可します
  • 他のパラメーター(ファイル名など)との組み合わせを許可します。

docopt(ファイル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 __== "__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 __== "__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}

「プロセス」および「アップロード」キーのブール値の代わりにカウンターがあることに注意してください。

結局のところ、これらの単語の重複を防ぐことはできません。

$ 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コマンドライン解析に適しています。

8
Jan Vlcinsky

これを行う最良の方法は、python inbuilt module 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()

コマンドラインで1つの引数のみを選択する場合は、グループの引数としてrequired = Trueを使用します。

group = parser.add_mutually_exclusive_group(required=True)
5
faizan baig

pythonプログラムを少なくとも1つのパラメーターで実行する必要がある場合は、does n'tオプションプレフィックス(デフォルトでは-または-)を持つ引数を追加します。 set nargs=+(1つ以上の引数が必要です)このメソッドの問題は、引数を指定しないと、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フラグには少なくとも1つの引数が必要です。optionnargs="+"がある場合、全体で少なくとも1つの引数が必要です。)

4
NuclearPeon

http://bugs.python.org/issue11588 このようなケースを処理するためにmutually_exclusive_groupコンセプトを一般化する方法を模索しています。

この開発でargparse.pyhttps://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」、「-up」、「-proc --up」などの入力を受け入れます。

エラーメッセージをより明確にする必要がありますが、最終的に 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は十分にクリアですか(グループのいずれかを受け入れます。少なくとも1つが必要です)。

  • 使用法(-p | -u)は明確ですか?必須の相互相互排他グループは同じものを生成します。代替の表記法はありますか?

  • phihag's単純なテストよりも直感的なこのグループを使用していますか?

4
hpaulj

おそらくサブパーサーを使用しますか?

import argparse

parser = argparse.ArgumentParser(description='Log archiver arguments.')
subparsers = parser.add_subparsers(dest='subparser_name', help='sub-command help')
parser_process = subparsers.add_parser('process', help='Process logs')
parser_upload = subparsers.add_parser('upload', help='Upload logs')
args = parser.parse_args()

print("Subparser: ", args.subparser_name)

--helpが表示されます:

$ python /tmp/aaa.py --help
usage: aaa.py [-h] {process,upload} ...

Log archiver arguments.

positional arguments:
  {process,upload}  sub-command help
    process         Process logs
    upload          Upload logs

optional arguments:
  -h, --help        show this help message and exit
$ python /tmp/aaa.py
usage: aaa.py [-h] {process,upload} ...
aaa.py: error: too few arguments
$ python3 /tmp/aaa.py upload
Subparser:  upload

これらのサブパーサーに追加のオプションを追加することもできます。また、dest='subparser_name'を使用する代わりに、特定のサブコマンドで直接呼び出される関数をバインドすることもできます(ドキュメントを参照)。

1
jhutar

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()
1
storm_m2138

これは目的を達成し、これは自動生成されたargparse --help出力。これは、ほとんどの正気なプログラマが望むものです(オプションの引数でも機能します)。

parser.add_argument(
    'commands',
    nargs='+',                      # require at least 1
    choices=['process', 'upload'],  # restrict the choice
    help='commands to execute'
)

これに関する公式ドキュメント: https://docs.python.org/3/library/argparse.html#choices

0
Bob