2009-08-04 15 views
4

Ich habe eine Anwendung, mit der Sie Ereignisdaten an ein benutzerdefiniertes Skript senden können. Sie legen einfach die Befehlszeilenargumente an und legen fest, welche Ereignisdaten zu welchem ​​Argument gehören. Das Problem ist, dass es hier keine wirkliche Flexibilität gibt. Jede Option, die Sie erstellen, wird verwendet, aber nicht jede Option hat notwendigerweise Daten. Wenn also die Anwendung die an das Skript zu sendende Zeichenkette erstellt, sind einige der Argumente leer und die OptionParser-Fehler von python sind mit "error: --someargument option erfordert ein Argument"Leere Optionen in Python analysieren

Da es über 200 Datenpunkte gibt, Es ist nicht so, dass ich separate Skripte schreiben könnte, um jede Kombination von möglichen Argumenten zu behandeln (es würde 2^200 Skripte benötigen). Gibt es eine Möglichkeit, leere Argumente in Pythons Optionsparser zu behandeln?

Antwort

8

Entschuldigung, missverstanden die Frage mit meiner ersten Antwort. Sie können optionale Argumente für Befehlszeilen-Flags verwenden, indem Sie den Aktionstyp Callback verwenden, wenn Sie eine Option definieren. Verwenden Sie die folgende Funktion als Rückruf (Sie wahrscheinlich Ihre Bedürfnisse anpassen werden wollen) und konfigurieren Sie es für jede der Flags, die optional ein Argument empfangen kann:

import optparse 

def optional_arg(arg_default): 
    def func(option,opt_str,value,parser): 
     if parser.rargs and not parser.rargs[0].startswith('-'): 
      val=parser.rargs[0] 
      parser.rargs.pop(0) 
     else: 
      val=arg_default 
     setattr(parser.values,option.dest,val) 
    return func 

def main(args): 
    parser=optparse.OptionParser() 
    parser.add_option('--foo',action='callback',callback=optional_arg('empty'),dest='foo') 
    parser.add_option('--file',action='store_true',default=False) 
    return parser.parse_args(args) 

if __name__=='__main__': 
    import sys 
    print main(sys.argv) 



Ausgeführt von der Befehlszeile Sie sehen:

# python parser.py 
(<Values at 0x8e42d8: {'foo': None, 'file': False}>, []) 

# python parser.py --foo 
(<Values at 0x8e42d8: {'foo': 'empty', 'file': False}>, []) 

# python parser.py --foo bar 
(<Values at 0x8e42d8: {'foo': 'bar', 'file': False}>, []) 
+0

Das Problem mit dieser Variante ist, dass '--for = bar' nicht funktioniert _parser.py: error: --foo Option nimmt keinen Wert' – Tobias

0

Ja, es ist ein Argument, dies zu tun, wenn Sie die Option hinzufügen:

from optparse import OptionParser 
parser = OptionParser() 
parser.add_option("--SomeData",action="store", dest="TheData", default='') 

Geben Sie den Standard Argument, um den Wert, den Sie die Möglichkeit haben wollen sie angegeben werden, sondern gegebenenfalls ein Argument haben .

+0

Ich bin mit dem Standard Diese Option wird nur verwendet, wenn --SomeData nicht in der Befehlszeile angegeben ist. Wenn Sie Folgendes tun: --SomeData --SomeMoreData blah, dann --SomeData-Fehler, weil kein Wert übergeben wurde. – directedition

+0

@directition Entschuldigung, ich habe Ihre Frage falsch verstanden. Eine andere Antwort mit einer Lösung, die für Sie arbeiten sollte. –

1

Ich glaube nicht, optparse kann dies tun. argparse ist ein anderes (nicht standardmäßiges) Modul, das handle situations like this haben kann, wobei die Optionen optionale Werte haben.

Mit optparse müssen Sie entweder die Option angeben, die ihren Wert enthält, oder beide weglassen.

0

optparse schon können Sie die leere Zeichenfolge als Option Argument zu übergeben. Wenn möglich, behandle die leere Zeichenfolge als "kein Wert". Für lange Optionen, eine der folgenden Arbeiten:

my_script --opt= --anotheroption 
my_script --opt='' --anotheroption 
my_script --opt="" --anotheroption 
my_script --opt '' --anotheroption 
my_script --opt "" --anotheroption 

für Kurzoptionen können Sie entweder verwenden:

my_script -o '' --anotheroption 
my_script -o "" --anotheroption 

Caveat: Diese wurde unter Linux getestet und sollten die gleiche Arbeit unter andere Unix-ähnliche Systeme; Windows behandelt die Befehlszeilenangabe anders und akzeptiert möglicherweise nicht alle der oben aufgeführten Varianten.

+0

Natürlich funktioniert das, aber es ist nicht das Gleiche wie einfach benutze 'my_script --opt'. – Tobias

0

Mark Roddys Lösung würde funktionieren, aber es erfordert Attributänderung eines Parser-Objekts während der Laufzeit und hat keine Unterstützung für andere alternative Formatierungen als - oder -. Eine etwas weniger aufwendige Lösung besteht darin, das sys.argv-Array vor dem Ausführen von optparse zu modifizieren und eine leere Zeichenfolge ("") nach einem Schalter einzufügen, der keine Argumente benötigt. Die einzige Einschränkung dieser Methode besteht darin, dass Sie für Ihre Optionen standardmäßig einen anderen vorhersehbaren Wert haben als den, den Sie in sys.argv einfügen (ich habe für das folgende Beispiel None gewählt, aber das spielt wirklich keine Rolle).

Der folgende Code erstellt einen Beispielparser und eine Reihe von Optionen, extrahiert ein Array zulässiger Schalter aus dem Parser (mit ein wenig Instanzvariable magic), iteriert dann durch sys.argv und findet jedes Mal ein erlaubte Schalter, es überprüft, um zu sehen, ob es gegeben wurde, ohne irgendwelche Argumente ihm zu folgen. Wenn nach einem Wechsel kein Argument vorhanden ist, wird die leere Zeichenfolge in den Befehl Zeile eingefügt. Nach dem Ändern von sys.argv wird der Parser aufgerufen, und Sie können nach Optionen suchen, deren Werte "" sind, und entsprechend handeln.

#Instantiate the parser, and add some options; set the options' default values to None, or something predictable that 
#can be checked later. 
PARSER_DEFAULTVAL = None 
parser = OptionParser(usage="%prog -[MODE] INPUT [options]") 
#This method doesn't work if interspersed switches and arguments are allowed. 
parser.allow_interspersed_args = False 
parser.add_option("-d", "--delete", action="store", type="string", dest="to_delete", default=PARSER_DEFAULTVAL) 
parser.add_option("-a", "--add", action="store", type="string", dest="to_add", default=PARSER_DEFAULTVAL) 

#Build a list of allowed switches, in this case ['-d', '--delete', '-a', '--add'] so that you can check if something 
#found on sys.argv is indeed a valid switch. This is trivial to make by hand in a short example, but if a program has 
#a lot of options, or if you want an idiot-proof way of getting all added options without modifying a list yourself, 
#this way is durable. If you are using OptionGroups, simply run the loop below with each group's option_list field. 
allowed_switches = [] 
for opt in parser.option_list: 
    #Add the short (-a) and long (--add) form of each switch to the list. 
    allowed_switches.extend(opt._short_opts + opt._long_opts) 

#Insert empty-string values into sys.argv whenever a switch without arguments is found. 
for a in range(len(sys.argv)): 
    arg = sys.argv[a] 
    #Check if the sys.argv value is a switch 
    if arg in allowed_switches: 
     #Check if it doesn't have an accompanying argument (i.e. if it is followed by another switch, or if it is last 
     #on the command line) 
     if a == len(sys.argv) - 1 or argv[a + 1] in allowed_switches: 
      sys.argv.insert(a + 1, "") 

options, args = parser.parse_args() 

#If the option is present (i.e. wasn't set to the default value) 
if not (options.to_delete == PARSER_DEFAULTVAL): 
    if options.droptables_ids_csv == "": 
     #The switch was not used with any arguments. 
     ... 
    else: 
     #The switch had arguments. 
     ... 
0

Nach der Überprüfung, dass der cp Befehl versteht z. --backup=simple aber nicht--backup simple, antwortete ich, das Problem wie folgt aus:

import sys 
from optparse import OptionParser 

def add_optval_option(pog, *args, **kwargs): 
    if 'empty' in kwargs: 
     empty_val = kwargs.pop('empty') 
     for i in range(1, len(sys.argv)): 
      a = sys.argv[i] 
      if a in args: 
       sys.argv.insert(i+1, empty_val) 
       break 
    pog.add_option(*args, **kwargs) 

def main(args): 
    parser = OptionParser() 
    add_optval_option(parser, 
         '--foo', '-f', 
         default='MISSING', 
         empty='EMPTY', 
         help='"EMPTY" if given without a value. Note: ' 
         '--foo=VALUE will work; --foo VALUE will *not*!') 
    o, a = parser.parse_args(args) 
    print 'Options:' 
    print ' --foo/-f:', o.foo 
    if a[1:]: 
     print 'Positional arguments:' 
     for arg in a[1:]: 
      print ' ', arg 
    else: 
     print 'No positional arguments' 

if __name__=='__main__': 
    import sys 
    main(sys.argv) 

Eigenwerbung: Dies ist Teil des opo Modul meiner thebops Paket ... ;-)