Konfigurationsdatei mit ConfigParser anlegen und prüfen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
martinjo
User
Beiträge: 186
Registriert: Dienstag 14. Juni 2011, 20:03

Hallo,

ich möchte meine Konfigurationsdateien zukünftig auslagern, bisher speichere ich die Werte noch all zu oft direkt in den Skripten. Ich habe mit ein Skript geschrieben, welches prüft, ob ob eine Konfigurationsdatei existiert und diese gegebenenfalls anlegt. Dann werden die Werte geprüft und auch diese ggf. angelegt.

Ich bin soweit zufrieden, glaube aber dass da noch erheblich was zu optimieren ist um den Code auch kleiner zu machen. Ich freue mich über Vorschläge. Danke

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf8 -*-

import os
from ConfigParser import SafeConfigParser

CONFIGFILE = os.path.join ( os.path.expanduser("~"), ".config/myconfigfile.ini" )

parser = SafeConfigParser()

CONFIGFILE_SECTION = "data"
CONFIGFILE_OPTIONS = [ "username", "password", "signatur", "environment" ]

def write_configfile( section, options ):
    with open( CONFIGFILE , "w" ) as configfile:
        print "writing config file ..."
        parser.add_section( section )
        for option in options:
            temp_input = raw_input( "please enter {0}: ".format( option) )
            parser.set( section, option, "{0}".format( temp_input ) )
        parser.write(configfile)
        
def updating_configfile( section, options ):
    with open( CONFIGFILE , "w+" ) as configfile:
        print "updating config file ..."
        if not section in parser.sections():
            parser.add_section( section )
        for option in options:
            temp_input = raw_input( "please enter {0}: ".format( option) )
            parser.set( section, option, "{0}".format( temp_input ) )
        parser.write(configfile)
        
def read_configfile( section, options ):
    print "reading config file", CONFIGFILE
    parser.read( CONFIGFILE )
    while not section in parser.sections():
        print "config file corrupt, writing new one ..."
        write_configfile( CONFIGFILE_SECTION, CONFIGFILE_OPTIONS )
    for option in [ "username", "password", "signatur", "environment" ]:
        if not parser.has_option( "data", option ):
            print "option {0} is missing".format( option )
        if parser.get( "data", option ) == "":
            print "option {0} has no value".format( option )
            updating_configfile( CONFIGFILE_SECTION, [ option ] )
            read_configfile( CONFIGFILE_SECTION, CONFIGFILE_OPTIONS )
            
## check configfile exists
if os.path.exists( CONFIGFILE ):
    print "configfile exists"
    read_configfile( CONFIGFILE_SECTION, CONFIGFILE_OPTIONS )
else:
    print "configfile not exists"
    write_configfile( CONFIGFILE_SECTION, CONFIGFILE_OPTIONS )
    read_configfile( CONFIGFILE_SECTION, CONFIGFILE_OPTIONS )
    
username    = parser.get( "data", "username")
password    = parser.get( "data", "password")    
signatur    = parser.get( "data", "signatur")    
environment = parser.get( "data", "environment")    

Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Zeile 16: Anstatt Debug-Infos per `print` auszugeben, solltest du diese besser an einen Logger übergeben. Mit `logging` existiert für diesen Zweck bereits ein Modul in der Standardbibliothek.

Zeile 20: `"{0}".format( temp_input )` ist sinnfrei, da zuvor ja bereits der User-Input als String vorliegt. Du kannst ihn also direkt verwenden. Im Übrigen ist in Format-Strings die Indexbezeichnung (hier: 0) seit Python 2.7 optional. Du hättest mittels `{}` also den selben Effekt.

Zeile 23: Verwende besser ein Verb, d.h. `updating_configfile()` => `update_configfile()`. Ich würde aber die Funktion wohl besser ganz weglassen. Updates können ja auf der Struktur, die dir die `configparser`-Bibliothek anbietet, vollzogen werden. Und dann schreibt man eben die komplette Struktur wieder neu in die Zieldatei rein.

Zeile 42: ``if parser.get( "data", option ) == ""`` lässt sich in Python auch als ``if not parser.get( "data", option )`` schreiben, da leere Strings in Python immer unwahr sind. Dies wirkt weniger kryptisch und verbessert IMHO den Lesefluss.

Ansonsten noch der Hinweis, dass Leeraum zwischen Klammern AFAIK nicht den Empfehlungen von PEP 8 entspricht.

Übrigens habe ich Fehlerarten, die mehrfach vorkommen, jeweils nur einmal beschrieben. Ein entsprechendes Mitdenken setze ich hier mal voraus... ;)
BlackJack

@martinjo: `CONFIGFILE_OPTIONS` kommen trotzdem noch einmal in dem Code vor. Konstanten definiert man doch damit das gerade nicht passiert/sein muss.

`parser` ist globel. Das ist IMHO nicht so günstig.

"w+" ist als Dateimodus gefährlich, das würde ich nur bei Binärdateien mit Strukturen mit fester Länge verwenden. So wie Du das anwendest kann eine kaputte Konfigdatei zurückbleiben, nämlich dann wenn der Benutzer neue Werte eingibt die kürzer sind als die alten. Dann würde die Datei eigentlich kürzer werden, tut sie aber nicht automagisch, also bleiben am Ende der Datei alte Daten vorhanden.

Ich persönlich ziehe ja mittlerweile JSON dem alten INI-Format vor. Man hat da gleich ein paar gängige Grundtypen statt nur Zeichenketten und man kann beliebig verschachteln und erweitern statt alles in eine ”flache” INI-Datei zu stecken. JSON ist zudem spezifiziert, kann also von mehr Sprachen gelesen und geschrieben werden. Es gibt zwar auch für alle möglichen Sprachen INI-Parser, aber das Format unterscheidet sich dann oft subtil.
Benutzeravatar
martinjo
User
Beiträge: 186
Registriert: Dienstag 14. Juni 2011, 20:03

Danke für die Antworten, werde ich mir zu Herzen nehmen.

@snafu: Die Leerzeichen habe ich gerade in allen Skripten angepasst, da ich glaubte das wäre PEP 8 konform :-) Hätte ich mal früher selbst nachgelesen, man soll sie wirklich weglassen.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf8 -*-

import os
import logging
from ConfigParser import SafeConfigParser

CONFIGFILE = os.path.join (os.path.expanduser("~"), ".config/myconfigfile.ini")
CONFIGFILE_SECTION = "data"
CONFIGFILE_OPTIONS = ["username", "password", "signatur", "environment"]

logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(message)s')
configfile_parser = SafeConfigParser()

def write_configfile(section=CONFIGFILE_SECTION, options=CONFIGFILE_OPTIONS):
    with open(CONFIGFILE , "w") as configfile:
        logging.info("writing config file ...")
        configfile_parser.add_section(section)
        for option in options:
            configfile_parser.set(section, option, "{0}".format(raw_input("please enter {0}: ".format(option))))
        configfile_parser.write(configfile)
        
def update_configfile(section=CONFIGFILE_SECTION, options=CONFIGFILE_OPTIONS):
    with open(CONFIGFILE , "r+") as configfile:
        logging.info("updating config file ...")
        if not section in configfile_parser.sections():
            configfile_parser.add_section(section)
        for option in options:
            configfile_parser.set(section, option, "{0}".format(raw_input("please enter {0}: ".format(option))))
        configfile_parser.write(configfile)
        
def read_configfile(section=CONFIGFILE_SECTION, options=CONFIGFILE_OPTIONS):
    logging.info("reading config file {}".format(CONFIGFILE))
    configfile_parser.read(CONFIGFILE)
    while not section in configfile_parser.sections():
        logging.warning("config file corrupt, writing new one ...")
        write_configfile()
    for option in ["username", "password", "signatur", "environment"]:
        if not configfile_parser.has_option("data", option):
            logging.warning("option {0} is missing".format(option))
        if not configfile_parser.get("data", option):
            logging.warning("option {0} has no value".format(option))
            update_configfile(options=[option])
            read_configfile()
            
## check configfile exists
if os.path.exists(CONFIGFILE):
    logging.info("configfile exists")
    read_configfile()
else:
    logging.info("configfile not exists")
    write_configfile()
    read_configfile()
    
username    = configfile_parser.get("data", "username")
password    = configfile_parser.get("data", "password")    
signatur    = configfile_parser.get("data", "signatur")    
environment = configfile_parser.get("data", "environment")    
Antworten