2016-04-07 16 views
0

私は、ユーザーが関数名を渡すことを可能にしようとしています。何らかの理由で、argparseは型チェック/変換を実行してから選択肢をチェックするようです。これはバグですか?一番いいことは?タイプの前にPython argparseチェックの選択

import argparse 

def foo(): 
    return 'foo' 

def bar(): 
    return 'bar' 

parser = argparse.ArgumentParser() 
functions = {f.__name__:f for f in [foo, bar]} 
parser.add_argument("function", type=lambda f: functions.get(f), help="which function", choices=functions) 
args = parser.parse_args() 
print(args.function()) 

これはスロー:

$ python blah.py foo 
usage: blah.py [-h] {foo,bar} 
blah.py: error: argument function: invalid choice: <function foo at 0x7f65746dd848> (choose from 'foo', 'bar') 
+2

実行されたので、 選択コンテ​​ナ内のオブジェクトのタイプは、指定されたタイプと一致する必要があります。 ' – wnnmaw

答えて

2

はい、構文解析中にtypeを入力した場合、choicesの順番は明確で意図的です(偶然ではありません)。 namespacearg_stringsを割り当てるために準備するときそれはありませんこれは、_get_valuesを呼び出します。

_get_valueaction.type機能を適用し、 choicesを解析するための _check_valueテスト

value not in action.choices 

のみ(inに応答してい

def _get_values(self, action, arg_strings) 
     .... (various nargs tests) 
     value = self._get_value(action, arg_string) 
     self._check_value(action, value) 
     return value 

__contains__)発現。

したがってchoicesは変換後の値を反映する必要があります。 typeintの場合、choices=[1,2,3]は正しく、['1','2','3']は正しくありません。

選択肢の表示にはいくつかの(ほとんど未解決の)バグの問題があります。長いリスト(例: range(100)は解析には役立ちますが、うまく表示されません。また、ディスプレイでは、choicesを反復可能にする必要があります(リスト、タプル、辞書など)。この表示の問題は、使用方法、ヘルプ、およびエラーメッセージ(それぞれが少し異なる形式のchoices)に影響します。

metavarは、望ましくないchoicesリストを置き換えるための最も強力なツールです。テストケースを実行して、3つの状況すべてで問題が解決するかどうかを確認する必要があります。選択肢のコンテナに含めるを 変換が有する任意のタイプの後に確認されていることを `注:[` argparse`(https://docs.python.org/3/library/argparse.html#choices)ドキュメントから

1

をどうやらので、しかし、あなたは、例えば、単にあなたの選択肢としてfunctions.keys()を使用することによってこの問題を回避することができますあなたは(マッピング関数はライン引数をコマンドに)インタフェースのこの種を提供する場合

import argparse 

def foo(): 
    return 'foo' 

def bar(): 
    return 'bar' 

parser = argparse.ArgumentParser() 
functions = {f.__name__:f for f in [foo, bar]} 
parser.add_argument("function", type=lambda f: functions.get(f), help="which function", choices=functions.values()) 
args = parser.parse_args() 
print(args.function()) 

ただし、clickを見てみたいことがあります。

+0

ええ、いくつかの明らかな回避策があります。また、単にtype = strを実行してから、関数[args.function]()を呼び出すこともできます。たいてい、私は心配しました。--helpは "type" ingの前に選択肢を表示しますが、パーサーは "type"の後に選択肢をチェックします。その状況に対処するための一般的な方法があることを期待していました。 – Scott

+0

Haが分かります。値が間違っていると誤った値を入力したときにエラーメッセージを表示するために 'str'をコマンドに使用することをお勧めします(' type = str、choices = functions.keys() ') ) ' – mfitzp

+1

「metavar = 'FUNCTION'」を指定してヘルプの「選択肢」を抑制し、単純な文字列操作で望むように選択肢をヘルプに追加することができます。それは私がやることだ、私はあなたの.values()提案と一緒に思う。どうも。 – Scott