2016-05-04 21 views
1

私は相互に排他的なオプションのグループを持つコマンドラインを解析したいと思います。通常、私はを使って、名前空間にはargs.foo = 'bar'python argparse store --foo = bar as args.key = 'foo'、args.value = 'bar'

を使用していますが、私は、これらのオプションのいくつかを下流に送る必要があります。私が本当に好きなのは、args.foo='bar'の代わりにargs.option_name = 'foo', args.option_value = 'bar'を自分の名前空間に戻すことです。私がやった何

は次のとおりです。--foo=barが解析されるとき

Namespace(thing_key='--foo', thing='bar') 

class KeyAction(argparse.Action): 
    def __call__(self, parser, namespace, values, option_string=None): 
     setattr(namespace, self.dest, values) 
     setattr(namespace, self.dest+'_key', option_string) 

frob = parser.add_mutually_exclusive_group() 
frob.add_argument('--foo', dest='thing', nargs='?', action=KeyAction) 
frob.add_argument('--nar', dest='thing', nargs='?', action=KeyAction) 

実行したときに、私の名前空間は次のようになります。もちろん、悲しいことに、--fooまたは--narが渡されない場合、namespace.thing_keyが定義されないため、getattr()を使用する必要があります。

機能のオーバーライドは機能的ですが、実際には適切ではないようです。

私はargparseの背後にある賢い人たちがすでに何らかの形でこの権利を持っていると思っています。私はそれをドキュメントと私の のargparse.pyから読んでいます。

これを行うには最高の、正しい、ピジョンソニックは何ですか?サブパーザル? 私はPython 3.5を使用しています。

このように、両方の答えのデータを使って、オプションを処理し、引数をとり、初期化時にすべてをうまく設定しました。

ヒント、手がかり、および検証いただきありがとうございます。私はこれが前にargparseに現れておらず、標準化された何かになるのに驚いています。 コーナーケースですが、相互排他的なオプションを使用するとコーナーケースの多くはありません。私はそれを理解したよう

class ValueAction(argparse.Action): 
     """Override to store both the format type as well as the argument""" 
     # pylint: disable=too-few-public-methods 
     def __init__(self, option_strings, dest, **kwargs): 
      self._dest = dest 
      dest = dest + '_arguments' 
      container = kwargs.pop('container') 
      kwargs['action'] = kwargs.pop('subaction') 
      action_class = container._pop_action_class(kwargs) 
      if not callable(action_class): 
       raise ValueError('unknown action "%s"' % (action_class,)) 
      self._action = action_class(option_strings, dest, **kwargs) 
      super().__init__(option_strings, dest, **kwargs) 

     def __call__(self, parser, namespace, values, option_string=None): 
      self._action(parser, namespace, values, option_string) 
      if isinstance(option_string, str): 
       while option_string[0] in parser.prefix_chars: 
        option_string = option_string[1:] 
      setattr(namespace, self._dest, option_string) 

答えて

1

サブクラスActionは、まさに開発者が期待しているものです。デフォルトの、最も一般的なアクションでも、「store」はサブクラスであるargparse._StoreActionです。 argparse._StoreTrueActionargparse._StoreConstActionのサブクラスで、defaultconstのデフォルトでのみ異なります。あなたはいくつかの方法でそれらを初期化する可能性が欠落している属性の場合に対処するために

set_defaultsあなたは関係なく、任意の引数は、それらを使用するかどうかの、いずれかのデフォルト値を定義することができます。サブパーザを使用するときに関数オブジェクトを名前空間に追加するために使用されるドキュメント。

parser.set_defaults(thing_key=None, thing=None) 

また、デフォルト値を持つ名前空間を作成し、parse_argsへ 引数としてそれを渡すことができます。

myNamespace = argparse.Namespace(thing_key=None, thing=None) 
parser.parse_args(names=myNamespace) 

あなたはargparse.SUPPRESSとしてのデフォルトを定義し、名前空間にfoo=Noneデフォルトを使用しない場合。

2

、あなたはあなたの両方が1つのネームスロットで使用されるオプション名を保存して行われ、いくつかの他のアクションのための更新プログラムを持っているように、複合アクションを指定できるようにしたいと思います。

group = argparse.mutually_exclusive_group() 
group.add_argument('--foo', action=StoreOption, subaction='store_true') 
group.add_argument('--bar', nargs='?', action=StoreOption, subaction='store') 

アクションクラスはStoreOptionですが、それはNamespaceオブジェクトに追加の更新を実行するためにsubactionで指定されたアクションを呼び出します。例えば、あなたのような何かを書くことができるようにしたいです。

私は(非常に限られたテストに)働いてしまったコードを以下に示す:

import argparse 

class StoreOption(argparse.Action): 
    def __init__(self, **kwargs): 
    kwargs['action'] = kwargs.pop('subaction') 
    container = kwargs.pop('container') 

    action_class = container._pop_action_class(kwargs) 
    if not callable(action_class): 
     raise ValueError('unknown action "%s"' % (action_class,)) 

    kwargs['dest'] = 'thing' 
    self._action = action_class(**kwargs) 
    print "_action:", self._action 

    super(StoreOption, self).__init__(
     option_strings= self._action.option_strings, 
     dest= self._action.dest, 
     nargs= self._action.nargs, 
     const= self._action.const, 
     default= self._action.default, 
     type= self._action.type, 
     choices= self._action.choices, 
     required= self._action.required, 
     help= self._action.help, 
     metavar= self._action.metavar) 

    def __call__(self, parser, namespace, values, option_string=None): 
    print "got here:", option_string, namespace 
    setattr(namespace, 'key', option_string) 
    self._action(parser, namespace, values, option_string) 

試験:

parser = argparse.ArgumentParser(prog='PROG') 
group = parser.add_mutually_exclusive_group() 
group.add_argument('--foo', container=group, action=StoreOption, subaction='store_true') 
group.add_argument('--bar', container=group, nargs=2, action=StoreOption, subaction='store') 

print parser.parse_args(['--bar', 'asd', 'qwe']) 
-- prints: Namespace(key='--bar', thing=['asd', 'qwe']) 

基本的StoreOptionは、別のアクション(で指定されたものをラップするアクションでありますsubaction)。引数を追加するときは、サブアクションを構築できるように、container=パラメータを渡す必要があります。また、サブアクションのために正しく設定するためには、キーワード引数に手を加えることもあります。

これもまた、テストが非常に限られているため、すべてのサブアクションでは機能しない可能性がありますが、正しい方向を指しているはずです。

関連する問題