2017-11-09 16 views
2

私たちは、使用しているコマンドラインツールでラッパースクリプトを構築しようとしています。ラッパースクリプトのオプションに基づいていくつかのツール引数を設定したいと考えています。ネイティブ引数をコマンドラインツールに直接渡す可能性もあります。コマンドラインで記述されているとおりです。ここでダッシュで始まるオプションの位置引数付きのargparse

は、私たちが思い付いたものです:

import argparse 

parser = argparse.ArgumentParser() 

parser.add_argument('positional') 
parser.add_argument('-f', '--foo', action='store_true') 
parser.add_argument('-b', '--bar', action='store_true') 

parser.add_argument('native_arg', nargs='*') 

args = parser.parse_args() 
print (args) 

positionalは必須です。 -f-bのオプションに基づいて、ツール呼び出しにいくつかのオプションが追加されます。後で残っているもの(あれば)は、ネイティブのツール引数として扱われ、ツールに直接与えられます。 -hで私たちのスクリプトを呼び出すと、次の利用状況を生成します。

usage: test.py [-h] [-f] [-b] positional [native_arg [native_arg ...]] 

トリックは、これらのネイティブの引数は、ツールのオプションそのものであり、例えば、-native0-native1のために、主要なダッシュを含有していることです。我々はすでにダブルダッシュでトリックについて知っているargparseより多くのオプションを探しています。次の呼び出し:

./test.py pos -- -native0 -native1 

が期待される解析された引数を生成します。

Namespace(bar=False, foo=False, native_arg=['-native0', '-native1'], positional='pos') 

はしかし、動作しません最初の位置引数の後にオプションを追加しようとしています。具体的には、次の呼び出し:印刷され、次のように、

./test.py --foo pos -- -native0 -native1 

が動作しているようです:positionals前に、オプションの引数を置く

usage: [...shortened...] 
test.py: error: unrecognized arguments: -- -native0 -native1 

./test.py pos --foo -- -native0 -native1 

は、次の出力を生成します:

Namespace(bar=False, foo=True, native_arg=['-native0', '-native1'], positional='pos') 

native_arg'+'の値をnargsに変更しても、上記のすべての状況に当てはまります(注意が必要ですが、少なくとも1つはnative_argと予想されます)。

私たちはPythonコードで何か間違っているのですか、これは何らかの種類のですか?argparse bug?

答えて

3

​​は、必須でない定位置引数とオプションの引数を混在させるのに苦労します(バグレポートの詳細については、https://stackoverflow.com/a/47208725/1399279を参照してください)。この問題を解決する方法を提案するのではなく、別のアプローチを提示するつもりです。

あなたが記述した状況のために作成されたparse_known_argsメソッドをチェックアウトする必要があります(つまり、ラップされたツールにオプションを渡す)。 parse_args異なり

In [1]: import argparse 

In [2]: parser = argparse.ArgumentParser() 

In [3]: parser.add_argument('positional') 

In [4]: parser.add_argument('-f', '--foo', action='store_true') 

In [5]: parser.add_argument('-b', '--bar', action='store_true') 

In [6]: parser.parse_known_args(['pos', '--foo', '-native0', '-native1']) 
Out[6]: (Namespace(bar=False, foo=True, positional='pos'), ['-native0', '-native1']) 

parse_known_argsの出力は、2つの要素のタプルです。最初の要素は、parse_argsから取得すると予想されるNamespaceインスタンスで、add_argumentの呼び出しで定義されたすべての属性が含まれています。 2番目の要素は、パーサに知られていないすべての引数のリストです。

私は個人的には、プログラムを呼び出す方法やエラーが発生しないオプションの順序を覚えておく必要がないため、この方法をお勧めします。

2

これは既知の問題です(https://bugs.python.org/issue15112argparse:オプションと別の位置が先行している場合NARGS =「*」位置引数は、任意の項目を受け付けていません)positionalsとoptionalsを扱う

解析交互に。ポジションを扱うとき、入力文字列が必要とする数だけ処理しようとします。しかし、?または*の位置は、文字列の空のリスト[]で満たされます。一方、+は、少なくとも1つの文字列

./test.py pos --foo -- -native0 -native1 

を必要とパーサはpositionalに「POS」を与え、native-arg[]。そして、オプションの '--foo'を与えます。残っている文字列が残っていないので、エラーが発生します。positionals

入力文字列の割り当ては、regexストリングマッチングの様式化された形式で行われます。 AA?のようなパターンと一致すると想像してください。

これを修正するには、先読みし、処理を遅らせる必要があります。native-arg。私たちはパッチを提案しましたが、実際には生産されていません。

@ SethMMortonの提案では、parse_known_argsを使用することをお勧めします。

以前のパーサー(たとえば、Optparse)は、フラグを付けられたすべての引数を処理しますが、残りの位置は未分類のリストとして返します。そのリストを分割するのはユーザーの責任です。​​は、positionalsの名前を付けて解析する機能を追加しましたが、アルゴリズムは固定nargsで最もよく機能し、あまりにも多くの変数nargsで不安定になります。

+0

私はまた、 '--'の前にあるものだけを解析し、残りを1つの大きなブロブとして取得するいくつかの方法に満足しています。 'parse_known_args'はスクリプトオプションのようなものを' native_args'に伝えることができます。私はそれについて少し考えており、2つの連鎖されたサブパワーの組み合わせで解けるかもしれません。ネイティブargsは主に他のスクリプトでも使用されるので、 '--'の前に常に終わるという回避策を使用することは受け入れられると思います。 –

+0

二重ダッシュは '-native0'のような文字列をどのように解釈するのかを変更しますが、 'positionals'にどのように割り当てられているかは変わりません。 'nargs = '...''、 'REMAINDER'もありますが、同じ割り当て問題があると思います。私は後でそれをテストすることができます。 – hpaulj

+0

私はそれを試して、それは '位置'が最初に見られた後すべてを食べる。つまり、 'test.py position --foo - -native0'では、' --foo'オプションが 'native_args'に集められます。 –

関連する問題