2013-03-20 12 views
9

私はいくつかのコードは、次の2つの方法で使用することができるようにすること​​を使用したい:2つの位置引数の相互排他的なグループを定義する方法は?

./tester.py all 
./tester.py name someprocess 

すなわちいずれかallは、いくつかの追加の文字列で指定OR nameされます。次のように

私が実装しようとしている:私は、エラー

ValueError: mutually exclusive arguments must be optional 

右のそれを行うにはどのように任意のアイデアを提供します

import argparse 
parser = argparse.ArgumentParser() 
group = parser.add_mutually_exclusive_group() 
group.add_argument('all', action='store_true', \ 
     help = "Stops all processes") 
group.add_argument('name', \ 
     help = "Stops the named process") 

print parser.parse_args() 

?私はこの場合にサブパーサーを避けたいと思います。 --nameは、リストで一つの値を必要とし、リストとして保存されます渡す

group.add_argument('--all', dest=is_all, action='store_true') 
group.add_argument('--name', dest=names, nargs='+') 

+0

なぜあなたはSUPのパーサを避けたいですか?これは、サブパーサーの問題のようです。 –

+0

彼らはすでにsuparser上で動作します。私はそれを浅くしたいと思っています...しかし、他の解決策がない場合、私は2つのレベルでサブパーザーを試してみます。 – Alex

+0

'all'を' --all'に、 'name'を' --name'に変更します。 – hughdbrown

答えて

-2

これは、あなたが探しているものと考えられます。

+1

コードを正しくフォーマットすると、 '--name'に何らかのエラーがあります。 –

0

「OR文字列をいくつか追加しました」

位置引数私はあなたのための最善の解決策は、(名前のtest.py)だと思います、追加の文字列に

を取ることができない。

import argparse 
p = argparse.ArgumentParser() 
meg = p.add_mutually_exclusive_group() 
meg.add_argument('-a', '--all', action='store_true', default=None) 
meg.add_argument('-n', '--name', nargs='+') 
print p.parse_args([]) 
print p.parse_args(['-a']) 
print p.parse_args('--name process'.split()) 
print p.parse_args('--name process1 process2'.split()) 
print p.parse_args('--all --name process1'.split()) 

$パイソンtest.py

Namespace(all=None, name=None) 
Namespace(all=True, name=None) 
Namespace(all=None, name=['process']) 
Namespace(all=None, name=['process1', 'process2']) 
usage: t2.py [-h] [-a | -n NAME [NAME ...]] 
t2.py: error: argument -n/--name: not allowed with argument -a/--all 
0

私はこれがサブパーサの問題のように見えることに同意するでしょう。もしあなたがを使ってオプションの引数にしたくないのであればtester.pyは、引数なしで呼び出された場合

  1. 、すべてのプロセスを停止:と--name、私から1つの提案は、ちょうど完全にallnameを無視し、次のセマンティクスを使用することです。
  2. tester.pyが引数を指定して呼び出された場合は、それらのプロセスのみを停止します。

    次のように動作します
    import argparse, sys 
    parser = argparse.ArgumentParser() 
    parser.add_argument('processes', nargs='*') 
    parsed = parser.parse(sys.argv[1:]) 
    print parsed 
    

     
    $ python tester.py 
    Namespace(processes=[]) 
    $ python tester.py proc1 
    Namespace(processes=['proc1']) 
    

    それとも、あなた自身の構文を主張する場合は、カスタムクラスを作成することができます使用して行うことができ

。私がallが指定されていると仮定しているので(実際にはnameが他の引数の1つである場合でも)残りの引数は無視され、nameが指定されていると仮定しているので、実際には「相互排他的なグループ」のケースはありません。それ以降はプロセスの名前とみなされます。次の動作と

import argparse 
import sys 
class AllOrName(argparse.Action): 
    def __call__(self, parser, namespace, values, option_string=None): 
     if len(values)==0: 
      raise argparse.ArgumentError(self, 'too few arguments') 
     if values[0]=='all': 
      setattr(namespace, 'all', True) 
     elif values[0]=='name': 
      if len(values)==1: 
       raise argparse.ArgumentError(self, 'please specify at least one process name') 
      setattr(namespace, 'name', values[1:]) 
     else: 
      raise argparse.ArgumentError(self, 'only "all" or "name" should be specified') 

parser = argparse.ArgumentParser() 
parser.add_argument('processes', nargs='*', action=AllOrName) 
parsed = parser.parse_args(sys.argv[1:]) 
print parsed 

 
$ python argparse_test.py name 
usage: argparse_test.py [-h] [processes [processes ...]] 
argparse_test.py: error: argument processes: please specify at least one process name 

$ python argparse_test.py name proc1 
Namespace(name=['proc1'], processes=None) 

$ python argparse_test.py all 
Namespace(all=True, processes=None) 

$ python argparse_test.py host 
usage: argparse_test.py [-h] [processes [processes ...]] 
argparse_test.py: error: argument processes: only "all" or "name" should be specified 

$ python argparse_test.py 
usage: argparse_test.py [-h] [processes [processes ...]] 
argparse_test.py: error: argument processes: too few arguments 
8

質問は歳ですが、すべての答えは異なる構文を示唆しているので、私はOPに近い何かを与えるでしょう。

まず、OPコードに問題:

位置store_trueは、(それが許可されている場合でも)、意味がありません。それは引数を必要としないので、常にTrueです。 「すべて」を与えるとerror: unrecognized arguments: allが生成されます。

他の引数は1つの値をとり、name属性に割り当てます。追加のprocess値は受け入れません。

mutually_exclusive_groupについては、そのエラーメッセージはparse_argsより前に発生します。そのようなグループが意味を成すためには、すべての選択肢はオプションでなければならない。これは、--フラグを持つか、またはnargs?または*に等しいというポスタリナルであることを意味します。グループ内に複数のポジションがあることは意味がありません。

--all--nameを使用する最も簡単な代替、このようなものになるだろう:

p=argparse.ArgumentParser() 
p.add_argument('mode', choices=['all','name']) 
p.add_argument('process',nargs='?') 

def foo(args): 
    if args.mode == 'all' and args.process: 
     pass # can ignore the process value or raise a error 
    if args.mode == 'name' and args.process is None: 
     p.error('name mode requires a process') 

args = p.parse_args() 
foo(args) # now test the namespace for correct `process` argument. 

受け入れ名前空間は、次のようになります。

Namespace(mode='name', process='process1') 
Namespace(mode='all', process=None) 

choicesはsubparsers引数の動作を模倣します。 parse_argsの後に独自のテストを行うのは、​​を特別なことをするより簡単なことが多いです。

+0

+1単純に、私は 'choices'を忘れていました。OPは' name'引数の後に1つのプロセス名しか必要としないことを注意深く読んでいませんでした。 – justhalf

0
import argparse 
parser = argparse.ArgumentParser() 
group = parser.add_mutually_exclusive_group(required=True) 
group.add_argument('-a','--all', action='store_true', \ 
     help = "Stops all processes") 
group.add_argument('-n','--name', \ 
     help = "Stops the named process") 

print parser.parse_args() 

./tester.py -h

usage: zx.py [-h] (-a | -n NAME) 

optional arguments: 
    -h, --help   show this help message and exit 
    -a, --all    Stops all processes 
    -n NAME, --name NAME Stops the named process 
関連する問題