2009-12-10 6 views
14

Ich habe optparse für eine Weile verwendet, und möchte die Möglichkeit hinzufügen, die Argumente aus einer Konfigurationsdatei laden.Verwenden einer Datei zum Speichern optparse Argumente

Bis jetzt ist das beste, was ich denken kann, ein Wrapper-Batch-Skript mit den hartcodierten Argumenten ... scheint klobig.

Was ist der eleganteste Weg, dies zu tun?

Antwort

22

Ich stimme mit S.Lott Idee einer Config-Datei zu verwenden, aber ich würde empfehlen, die eingebauten in ConfigParser (ConfigParser in 3.0) Modul es zu analysieren, anstatt eine selbstgebraute Lösung.

Hier ist ein kurzes Skript, das ConfigParser und optparse in Aktion veranschaulicht.

import ConfigParser 
from optparse import OptionParser 

CONFIG_FILENAME = 'defaults.cfg' 

def main(): 
    config = ConfigParser.ConfigParser() 
    config.read(CONFIG_FILENAME) 

    parser = OptionParser() 
    parser.add_option("-l", 
         "--language", 
         dest="language", 
         help="The UI language", 
         default=config.get("Localization", "language")) 
    parser.add_option("-f", 
         "--flag", 
         dest="flag", 
         help="The country flag", 
         default=config.get("Localization", "flag")) 

    print parser.parse_args() 

if __name__ == "__main__": 
    main() 

Ausgang:

(<Values at 0x2182c88: {'flag': 'japan.png', 'language': 'Japanese'}>, []) 

Run mit "parser.py --language=French "

(<Values at 0x2215c60: {'flag': 'japan.png', 'language': 'French'}>, []) 

Hilfe gebaut in Run mit" parser.py --help":

Usage: parser.py [options] 

Options: 
    -h, --help   show this help message and exit 
    -l LANGUAGE, --language=LANGUAGE 
         The UI language 
    -f FLAG, --flag=FLAG The country flag 

Die Konfigurationsdatei:

[Localization] 
language=Japanese 
flag=japan.png 
3

Das ist, was die set_defaults Funktion ist. http://docs.python.org/library/optparse.html#optparse.OptionParser.set_defaults

Erstellen Sie eine Datei, die das Wörterbuch der Standardwerte ist.

{ 'arg1': 'this', 
'arg2': 'that' 
} 

Dann diese Datei lesen, eval es den Text in ein Wörterbuch zu konvertieren, und bieten dieses Wörterbuch als Argumente zu set_defaults.

Wenn Sie sich wirklich Sorgen um eval machen, dann verwenden Sie JSON (oder YAML) -Notation für diese Datei. Oder Sie könnten sogar eine .INI Datei daraus machen und configparser verwenden, um Ihre Standardeinstellungen zu erhalten.

Oder Sie können eine einfache Liste von Zuordnung Anweisungen und exec verwenden.

Konfigurationsdatei.

arg1 = 'this' 
arg2 = 'that' 

Lesen der Konfigurationsdatei.

defaults= {} 
with open('defaults.py','r') as config 
    exec config in {}, defaults 
+0

Es gibt keinen Grund, hier eval zu verwenden - Sie können nur Marschall verwenden. –

+1

@Nick Bastin: Eval ist nicht böse, nur die soziopathischen Endbenutzer, die immer versuchen, die Anwendung zu hacken, indem sie Eval ausnutzen. –

+0

Wackeln Sie mit dem Finger auf einen Angreifer, der einen Riss in Ihrer Rüstung ausnutzt, beseitigt weder den Riss noch stoppt er den Angriff ... :) –

7

Sie argparse Modul für das verwenden:

>>> open('args.txt', 'w').write('-f\nbar') 
>>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@') 
>>> parser.add_argument('-f') 
>>> parser.parse_args(['-f', 'foo', '@args.txt']) 
Namespace(f='bar') 

Es könnte in stdlib aufgenommen werden, siehe pep 389.

+4

PEP 389 wurde genehmigt und 'argparse' ist bereits Teil von Python 2.7 – sorin

4

Ich hatte ein ähnliches Problem, wollte aber auch die Config-Datei als Argument angeben. Inspiriert von S. Lott's Antwort, kam ich auf den folgenden Code.

Beispiel Terminalsitzung:

$ python defaultconf.py # use hard-coded defaults 
False 
$ python defaultconf.py --verbose # verbose on command line 
True 
$ python defaultconf.py --loadconfig blah # load config with 'verbose':True 
True 
$ python defaultconf.py --loadconfig blah --quiet # Override configured value 
False

Code:

#!/usr/bin/env python2.6 
import optparse 

def getParser(defaults): 
    """Create and return an OptionParser instance, with supplied defaults 
    """ 
    o = optparse.OptionParser() 
    o.set_defaults(**defaults) 
    o.add_option("--verbose", dest = "verbose", action="store_true") 
    o.add_option("--quiet", dest = "verbose", action="store_false") 

    o.add_option("--loadconfig", dest = "loadconfig") 

    return o 


def main(): 
    # Hard coded defaults (including non-command-line-argument options) 
    my_defaults = {'verbose': False, 'config_only_variable': 42} 

    # Initially parse arguments 
    opts, args = getParser(my_defaults).parse_args() 

    if opts.loadconfig is not None: 
     # Load config from disk, update the defaults dictionary, and reparse 
     # Could use ConfigParser, simplejson, yaml etc. 

     config_file_values = {'verbose': True} # the dict loaded from disk 

     my_defaults.update(config_file_values) 
     opts, args = getParser(my_defaults).parse_args() 

    print opts.verbose 

if __name__ == '__main__': 
    main() 

Eine praktische Implementierung kann auf Github zu finden: The defaults dictionary, the argument parser und the main function

+0

Das ist großartig. Ich habe es erweitert, um auch die Standardwerte aus der Konfigurationsdatei in --help anzuzeigen: –

2

Lesen Sie die Argumente in der gleichen Kommandozeilen-Format aus einer Datei z @Befehle, dann verwenden Sie Ihren ursprünglichen Parser, um sie zu analysieren.

options, args = parser.parse_args() 

if args[0][0] == '@': # script.py @optfile 
    with open(args[0][1:]) as f: 
     fa = [l.strip() for l in f] 
    fa = fa + args[1:] # put back any other positional arguments 
    # Use your original parser to parse the new options 
    options, args = parser.parse_args(args=fa, values=options) 
0

Ich habe in letzter Zeit eine Menge von Skripten mit Fahnen und Optionen gebaut, und ich habe kommen mit der Lösung here beschrieben.

Grundsätzlich ich Instanz ein Optionsparser mit einem speziellen Flag, das sagt, Optionen aus einer Datei zu laden und zu laden, so können Sie normalerweise Ihr Skript verwenden Optionen aus der Befehlszeile angeben oder sie (oder eine Reihe von ihnen) aus einer Datei.

Update: Ich habe Code geteilt auf GitHub

Verwandte Themen