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


92

私は、またはその両方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つのパラメーターがないと意味がありません。argparse少なくとも1つのパラメーターを強制的に選択するように構成するにはどうすればよいですか?

更新:

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


9
-x普遍的にフラグであり、オプションです。-必要に応じてカットします。

1
processデフォルトの動作(オプションを指定する必要なし)を作成しuploadそのオプションが設定されている場合にユーザーがに変更できるようにできないでしょうか?通常、オプションはオプションであるため、名前が付けられます。必要なオプションは避けてください(これもargparse ドキュメントにあります)。
Tim Pietzcker

@AdamMatan質問をしてから約3年になりますが、私はそれに隠された課題を気に入り、この種のタスクに利用できる新しいソリューションの利点を利用しました。
Jan Vlcinsky、2014年

回答:


107
if not (args.process or args.upload):
    parser.error('No action requested, add -process or -upload')

1
これにargparse組み込みオプションがない場合は、それがおそらく唯一の方法です。
アダムMatan

29
args = vars(parser.parse_args())
if not any(args.values()):
    parser.error('No arguments provided.')

3
一般化されたソリューションの場合は+1。また、の使用と同様に、vars()**を使用してコンストラクタに慎重に名前を付けたオプションを渡すのにも役立ちます。
レナ

それはまさに私がそれでやっていることです。ありがとう!
ブレントランス2013年

1
ダン、私はそれが好きですvars。私は.__dict__前にやっただけで馬鹿げたことを感じました。
Theo Belaire、2014

1
素晴らしい答え。「vars」と「any」はどちらも私にとって新しいものでした:-)
Vivek Jha

21

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

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

ただし、おそらくサブコマンドを代わりに使用する方が良いでしょう。


4
彼はXORではなく--processOR を許可したいと思います--upload。これにより、両方のオプションが同時に設定されなくなります。
phihag

+1あなたはサブコマンドについて述べたので。まだ-誰かがコメントで指摘したように-x--xxx通常はオプションのパラメータです。
Mac

20

私はこれが汚れとして古いことを知っていますが、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  

3
残念ながら、OPはXORを望んでいません。それはどちらかまたは両方ですが、どれもないため、最後のテストケースは要件を満たしていません。
kdopen 2015年

2
@kdopen:回答者は、これが元の質問のバリエーションであることを明らかにしました。これは私が有用であることがわかりました:「1つのオプションを必要とするが、複数のオプションを禁止する方法」 。しかし、この回答がここにあると助けになります...
erik.weathers

2
この投稿は最初の質問には答えません
Marc

2
これは「少なくとも1つ」の質問にどのように答えますか?
xaxxon

2
残念ながら、OPはXORを望んでいません。
duckman_1991

8

要件のレビュー

  • 使用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 __name__ == "__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 __name__ == "__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、コマンドライン解析に適しています。


docoptについて聞いたことがない、素晴らしい提案!
Ton van den Heuvel、2015

@TonvandenHeuvelいいね。確認したいのですが、コマンドラインインターフェイスの推奨ソリューションとしてまだ使用しています。
Jan Vlcinsky、2015

ベストアンサーevar、詳細な例をお寄せいただきありがとうございます。
jnovack 2016

5

少なくとも1つのパラメーターを使用してPythonプログラムを実行する必要がある場合は、オプションの接頭辞を持たない引数(デフォルトでは-または-)を追加し、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()

私は考えてあなたがオプションの接頭辞と引数を追加するとき、NARGSは全体の引数パーサだけでなく、オプションを支配していること。(私の平均である、あなたが持っている場合--optionとのフラグnargs="+"は、--optionフラグを期待少なくとも一つの引数をお持ちの場合optionnargs="+"、それが全体の少なくとも一つの引数を期待しています。)


choices=['process','upload']その引数に追加できます。
hpaulj 2014年

5

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単純なテストよりも直感的ですか?


add_usage_groupこのページで私は言及を見つけることができません:docs.python.org/2/library/argparse.html ; そのドキュメントへのリンクを提供していただけますか?
P.マイヤーノア

@ P.MyerNore、私はリンクを提供しました-この回答の最初に。これはまだ生産されていません。
hpaulj 2018年

5

これを行う最良の方法は、Pythonの組み込みモジュール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)

2
これはどのようにして「少なくとも1つ」を取得しますか?「正確に1つ」を取得しませんか?
xaxxon

3
残念ながら、OPはXORを望んでいません。OPはORを探しています
duckman_1991

これはOPの質問に答えなかったが、それはとにかく感謝して鉱山に答え_(ツ)_ /¯
rosstex

2

たぶんサブパーサーを使用しますか?

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'特定のサブコマンドで直接呼び出される関数をバインドすることもできます(ドキュメントを参照)。


2

これは目的を達成し、これは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


1

アクションのリストに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()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.