web-dev-qa-db-ja.com

python argparseのカスタムタブ補完

Pythonスクリプトでargparseと連携してシェルタブ補完を取得する方法は?

#!/usr/bin/env python
import argparse

def main(**args):
    pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('positional', choices=['spam', 'eggs'])
    parser.add_argument('--optional', choices=['foo1', 'foo2', 'bar'])
    args = parser.parse_args()
    main(**vars(args))

.pyファイルに実行可能フラグを設定すると、期待される結果は次のようになります。

$ ./example.py sp<tab>             
   ->  completes to "./example.py spam"
$ ./example.py --op<tab> 
   ->  completes to "./example.py --optional"
$ ./example.py --optional b<tab>
   ->  completes to "./example.py --optional bar"
$ ./example.py --optional f<tab>   
   ->  completes to "./example.py --optional foo"
       and, additionally, prints  "foo1  foo2"  choices on stdout on a new line
35
wim

Andrey Kislyukによる argcomplete をご覧ください。

それをインストールします:

_pip install argcomplete
_

モジュールをインポートし、parser.parse_args()を呼び出す前にソースに1行追加します。

_#!/usr/bin/env python

import argparse as ap
import argcomplete

def main(**args):
  pass

if __name__ == '__main__':
  parser = ap.ArgumentParser()
  parser.add_argument('positional', choices=['spam', 'eggs'])
  parser.add_argument('--optional', choices=['foo1', 'foo2', 'bar'])
  argcomplete.autocomplete(parser)
  args = parser.parse_args()
  main(**vars(args))
_

そして、bashがこのスクリプトを認識していることを確認するには、次を使用します。

_eval "$(register-python-argcomplete your_script)"
_

その行を_~/.bashrc_に入れるか、argcompleteのドキュメントに従って、「グローバル」補完をアクティブにする必要があります。

その後、完了は要求どおりに機能します。

これが機能する方法は、eval行がcompleteを使用して登録される関数__python_argcomlete_を作成することです。 (_register-python-argcomplete your_script_を実行して、bashに評価されるものを確認します)。オートコンプリート機能は、動作する必要があるかどうかを確認するために、bash完了メカニズムによって設定された環境変数を探します。動作した場合、プログラムを終了します。動作しない場合、これはプログラムへの通常の呼び出しであり、関数は何も実行せず、プログラムの通常のフローが続行されます。

52
Anthon

オートコンプリートが機能するためには、可能なオプションを生成するbash関数が必要です。次に、complete -F <function_name> <program_name>を実行する必要があります。

これを行う最良の方法は、プログラムが独自の解析アルゴリズムに基づいて完了関数を生成し、重複を回避することです。しかし、argparseをざっと見ただけで、内部構造にアクセスする方法が見つかりませんでしたが、探すことをお勧めします。

上記のプログラムで実行するbash関数を次に示します。

function _example_auto() {
    local cur=${COMP_WORDS[COMP_CWORD]}
    local prev=${COMP_WORDS[COMP_CWORD-1]}

    case "$prev" in
    --optional ) 
        COMPREPLY=( $(compgen -W "foo1 foo2 bar" -- $cur) )
        return 0
        ;;
    *)
        COMPREPLY=( $(compgen -W "--optional spam eggs" -- $cur) )
        return 0
        ;;
    esac
}
3
Sorin