2012-07-12 10 views
12

W moim skrypcie python chcę móc użyć opcjonalnego parametru wejściowego tylko, gdy podano inny opcjonalny parametr. Przykład:python, argparse: włącz parametr wejściowy, gdy podano inny.

$ python myScript.py --parameter1 value1 
$ python myScript.py --parameter1 value1 --parameter2 value2 

lecz nie:

$ python myScript.py --parameter2 value2 

Jak mogę to zrobić z argparse?

Dzięki!

+1

Czego chcesz się zdarzyć, jeśli 'myScript.py --parameter2 value2 --parameter1 value1'? Jest to bardzo trudny przypadek, jeśli chcesz go przekazać. – mgilson

+1

http://bugs.python.org/issue11588 to żądanie błędu dla funkcji 'mutualually_inclusive_group'. W tym przypadku nie będzie to działać, ponieważ '--parametr1' może wystąpić bez' --parametru2'. Przyczyń się do tego problemu, jeśli masz pomysły na to, w jaki sposób można wdrożyć te ograniczenia lub związane z nimi ograniczenia. – hpaulj

Odpowiedz

10

Użyj akcję niestandardową:

import argparse 

foo_default=None  

class BarAction(argparse.Action): 
    def __call__(self,parser,namespace,values,option_string=None): 
     didfoo=getattr(namespace,'foo',foo_default) 
     if(didfoo == foo_default): 
      parser.error("foo before bar!") 
     else: 
      setattr(namespace,self.dest,values) 

parser=argparse.ArgumentParser() 
parser.add_argument('--foo',default=foo_default) 
parser.add_argument('--bar',action=BarAction,help="Only use this if --foo is set") 

#testing. 
print parser.parse_args('--foo baz'.split()) 
print parser.parse_args('--foo baz --bar cat'.split()) 
print parser.parse_args('--bar dog'.split()) 

Można to zrobić nawet w trochę łatwiej utrzymać drogę, jeśli jesteś OK z opierając się na pewnym nieudokumentowane zachowania argparse:

import argparse 

parser=argparse.ArgumentParser() 
first_action=parser.add_argument('--foo',dest='cat',default=None) 

class BarAction(argparse.Action): 
    def __call__(self,parser,namespace,values,option_string=None): 
     didfoo=getattr(namespace,first_action.dest,first_action.default) 
     if(didfoo == first_action.default): 
      parser.error("foo before bar!") 
     else: 
      setattr(namespace,self.dest,values) 

parser.add_argument('--bar',action=BarAction, 
        help="Only use this if --foo is set") 

#testing. 
print parser.parse_args('--foo baz'.split()) 
print parser.parse_args('--foo baz --bar cat'.split()) 
print parser.parse_args('--bar dog'.split()) 

W w tym przykładzie otrzymujemy domyślną wartość dla foo i jest to miejsce docelowe z obiektu akcji zwróconego przez add_argument (wartość zwracana przez add_argument nie jest udokumentowana nigdzie, co mogę znaleźć). To wciąż jest trochę delikatne (jeśli chcesz, na przykład, podać słowo kluczowe type= do argumentu --foo).

Na koniec można sprawdzić sys.argv przed analizą.

import sys 
if ("--parameter2" in sys.argv) and ("--parameter1" not in sys.argv): 
    parser.error("parameter1 must be given if parameter2 is given") 

To staje się trochę bardziej skomplikowane, jeśli --parameter1 może być również wywołane przez --p1, ale masz pomysł. Następnie można użyć tej opcji, ponieważ nie wymaga żadnej określonej kolejności. (--p2 nie musi być zgodna z --p1 w linii poleceń). I tak jak poprzednio, możesz uzyskać listę ciągów poleceń, które wyzwalają określone działanie za pomocą atrybutu option_strings zwróconego przez parser.add_argument(...). na przykład

import argparse 
import sys 
parser=argparse.ArgumentParser() 
action1=parser.add_argument('--foo') 
action2=parser.add_argument('--bar', 
          help="Only use this if --foo is set") 

argv=set(sys.argv) 
if ((argv & set(action2.option_strings)) and 
     not (argv & set(action1.option_strings))): 
       #^ set intersection 
    parser.error(' or '.join(action1.option_strings)+ 
        ' must be given with '+ 
        ' or '.join(action2.option_strings)) 
2

Jednym z pomysłów byłoby ręcznie sprawdzić wyjście nazywając parser.parse_args() i podnieść wyjątek lub w inny sposób, jeśli nie jest używany, ale --parameter2--parameter1 nie jest.

Możesz także spróbować ustawić custom action (przewiń w dół) do --parameter2 sprawdź, czy --parameter1 istnieje w przestrzeni nazw.

Wreszcie możesz spróbować użyć opcji subparsers, chociaż nie wiem, czy pozwoli ci podać wartość dla --parameter1.

2

Możesz użyć parse_known_args(), aby sprawdzić, czy podano --parameter1, zanim dodasz --parameter2 do analizatora składni.

import argparse 

parser = argparse.ArgumentParser() 
parser.add_argument('--parameter1', dest='p1') 
args = parser.parse_known_args()[0] 
if args.p1: 
    parser.add_argument('--parameter2', dest='p2') 
args = parser.parse_args() 

if args.p1: 
    print args.p1 
if args.p2: 
    print args.p2 

Wyniki:

$ python myScript.py --parameter1 a 
a 
$ python myScript.py --parameter1 a --parameter2 b 
a 
b 
$ python myScript.py --parameter2 b 
usage: myScript.py [-h] [--parameter1 P1] 
myScript.py: error: unrecognized arguments: --parameter2 b 
+2

'--help' będzie niedokładne. – pmav99

Powiązane problemy