2012-07-12 3 views
12

In meinem Python-Skript möchte ich einen optionalen Eingabeparameter nur verwenden können, wenn ein anderer optionaler Parameter angegeben wurde. Beispiel:Python, argparse: Eingabeparameter aktivieren, wenn ein anderer angegeben wurde

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

aber nicht:

$ python myScript.py --parameter2 value2 

Wie mache ich das mit argparse?

Danke!

+1

Was möchten Sie tun, wenn 'myScript.py --parameter2 Wert2 --parameter1 Wert1 passieren? Dies ist ein sehr schwieriger Fall, wenn Sie möchten, dass er besteht. – mgilson

+1

http://bugs.python.org/issue11588 ist eine Fehleranforderung für eine Funktion 'wechselseitig_inklusive_Gruppe'. Das würde in diesem Fall nicht ganz funktionieren, da '-Parameter1' ohne' -Parameter2' auftreten kann. Tragen Sie zu diesem Problem bei, wenn Sie Ideen haben, wie diese oder ähnliche Einschränkungen implementiert werden könnten. – hpaulj

Antwort

10

eine benutzerdefinierte Aktion verwenden:

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()) 

Dies kann sogar in ein wenig leichter gemacht werden Art und Weise zu pflegen, wenn Sie mit unter Berufung auf einige undokumentierte Verhalten von argparse OK sind:

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()) 

In In diesem Beispiel erhalten wir den Standard für foo und sein Ziel aus dem Aktionsobjekt, das von add_argument zurückgegeben wird (der Rückgabewert von add_argument ist nirgendwo dokumentiert, das ich finden kann). Dies ist immer noch etwas fragil (Wenn Sie beispielsweise ein type= Schlüsselwort für das Argument --foo angeben möchten).

Schließlich können Sie überprüfen sys.argv vor dem Parsen.

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

Dies wird ein wenig komplizierter, wenn --parameter1 auch durch --p1 ausgelöst werden könnte, aber Sie bekommen die Idee. Dann können Sie

verwenden
if (set(sys.argv).intersection(('--p2',...)) and 
    not set(sys.argv).intersection(('--p1',...))) 

Der Vorteil hier ist, dass es keine bestimmte Reihenfolge erfordert. (--p2 muss nicht --p1 auf der Kommandozeile folgen). Und wie zuvor können Sie die Liste der Befehlszeichenfolgen abrufen, die Ihre bestimmte Aktion über das option_strings-Attribut auslösen, das von parser.add_argument(...) zurückgegeben wird. z.B.

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

Eine Idee wäre, manuell die Ausgabe überprüfen parser.parse_args() aufrufen und eine Ausnahme auslösen oder sonst fehlschlagen, wenn --parameter2 verwendet wird, aber --parameter1 nicht.

Sie könnten auch versuchen, einen custom action (ein wenig nach unten scrollen) zu --parameter2 überprüfen, ob --parameter1 innerhalb des Namespace existiert.

Schließlich können Sie versuchen, subparsers verwenden, obwohl ich nicht weiß, ob Sie einen Wert für --parameter1 angeben können.

2

Sie können parse_known_args() verwenden, um zu überprüfen, ob --parameter1 vor dem Hinzufügen --parameter2 zum Parser gegeben wurde.

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 

Ergebnisse:

$ 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' wird jedoch ungenau sein. – pmav99

Verwandte Themen