very simple CFG-Parser...

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab einen wirklich einfachen CFG-Parser geschrieben...

Code: Alles auswählen

# SimpleCfg.py
from os import path
from os import environ
class cfg:
    def __init__(self,Datei):
        if not path.isfile(Datei):
            raise "Datei "+Datei+" existiert nicht! Aktueller Pfad:",path.abspath(".")
        try:
            CfgDatei=open(Datei,"r")
        except:
            raise "Öffnen von:"+Datei+" fehlgeschlagen!"

        self.CfgDaten={}
        while 1:
            Zeile = CfgDatei.readline()
            if not Zeile:
                break
            if not Zeile[0]=="#" and ":" in Zeile:
                Daten=Zeile.split(":")
                self.CfgDaten[Daten[0].strip()]=Daten[1].strip()

        CfgDatei.close()

    def getItem(self,Item,ErrorHandling=False):
        if Item in self.CfgDaten:
            return self.CfgDaten[Item]
        elif ErrorHandling:
            return False
        else:
            raise "Item: [",Item,"] nicht in Cfg-Datei gefunden!"
Eine Beispiel CFG-Datei:

Code: Alles auswählen

# Beispiel.cfg
# Kommentar
Name: Wert
Wert: 1
Python ist wie?: Python ist super!
Zum Ausführen:

Code: Alles auswählen

# test.py
import SimpleCfg
MyCfg=SimpleCfg.cfg("Beispiel.cfg")
print MyCfg.getItem("Name")
print MyCfg.getItem("Wert")
print MyCfg.getItem("Python ist wie?")
Und das kommt raus:

Code: Alles auswählen

Wert
1
Python ist super!

Zu beachten ist, das alle Ergebnisse erstmal ein String sind. Also auch Wert=1 ist eigentlich Wert="1" :)

Das "ErrorHandling" bei der Funktion getItem produziert Standartmäßig einen fehler, wenn ein Wert nicht gefunden wird, aber so kann man es verhindern:
print MyCfg.getItem("NichtVorhanden", True)

Dann erhält man nur ein False zurück und kann es irgendwie anders handeln...
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi jens,

hast Dir schonmal den Configparser von Python angeschaut, oder das ->
http://python.sandtner.org/viewtopic.php?t=1785 ?


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Den Configparser von Python kenne ich noch nicht... Ist aber wahrscheinlich Overkill, oder???

Der andere Thread ist aber super! Danke :lol:
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich hab mir nun doch den eingebauten ConfigParser angeschaut... Dumm dabei ist, wenn Fehler in der Config-Datei sind (z.B. fehlende Angaben) dann schlägt immer ein Traceback zum Anwender durch...
Deswegen hab ich mir eine "Hilfs"-Klasse ausgedacht, die "normale" Fehlermeldungen ausspuckt:

Code: Alles auswählen

import sys, os, ConfigParser

config_file = "MeineTolleKonfigurationsDatei.conf"

class Parser:
    def __init__( self ):
        self.current_section = ""
        if not os.path.isfile( config_file ):
            self.Fehler( "file not found!" )

        self.cfg = ConfigParser.RawConfigParser()
        self.cfg.read( config_file )

    def set_section( self, section ):
        self.current_section = section

    def get( self, option, item_type = "str" ):
        self.check( option )
        if item_type == "str":
            return self.cfg.get( self.current_section, option )
        elif item_type == "int":
            return self.cfg.getint( self.current_section, option )

    def check( self, option ):
        if not self.cfg.has_section( self.current_section ):
            self.error( "section '[%s]' not found!" % self.current_section )
        if not self.cfg.has_option( self.current_section, option ):
            self.error( "in section '[%s]' option '%s' not found!" %
                (self.current_section, option) )

    def error( self, txt ):
        print "error in Config File '%s':" % config_file
        print txt
        sys.exit()
BlackJack

Es wäre wohl sinnvoller einfach die Ausnahmen zu behandeln statt selbst zu prüfen was sowieso schon geprüft wird um eben die Ausnahmen zu erzeugen.

Und möchte man wirklich das ein Programm jedes mal komplett abbricht nur weil ein Wert nicht in der Datei steht? Es gibt doch sicher viele Einstellungen für die man eine sinnvolle Voreinstellung in das Programm einbauen kann.

Die check()-Methode würde ich mir jedenfalls komplett sparen und einfach in get() auf die entsprechenden Ausnahmen reagieren.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Naja, ich dachte vorher-checken ist sinnvoller als exceptions Abzufangen... Damit habe ich auch einen kürzeren Code, weil ich check() nur einmal aufrufen muß...
Natürlich sind immer noch exceptions Möglich, z.B. wenn ein getint() ausgeführt wird aber keine Zahl vorliegt...

Mit Vorgabewerten ist mit glaub ich zu kompliziert :?
BlackJack

Voher prüfen ist eher "unpythonic". Lies mal die Erklärung zu EAFP im Glossar vom Tutorial von der Python-Doku.

Empfohlener Stil ist es davon auszugehen das alles klappt und mit try/except Abzufangen was nicht funktioniert hat. Und der ConfigParser hat extra zwei schöne Ausnahmen für nicht vorhandene Abschnitte und Optionen.

Kann man z.B. so nutzen:

Code: Alles auswählen

#!/usr/bin/env python
import os, sys, new
from ConfigParser import RawConfigParser, NoSectionError, NoOptionError

class Parser:
    def __init__(self, filename, defaults=None):
        self.current_section = None
        self.filename = filename
        if not os.path.isfile(filename):
            raise IOError('File %r does not exist.' % filename)
        self.config = RawConfigParser(defaults)
        self.config.read(filename)
        
        # Create self.get*() methods.
        for getter_name in ['get' + item_type
                            for item_type in ('', 'boolean', 'float', 'int')]:
            get_method = getattr(self.config, getter_name)
            setattr(self, getter_name,
                    new.instancemethod(self._getter_factory(get_method),
                                       self, self.__class__))
    
    def set_section(self, section_name):
        self.current_section = section_name
    
    def _getter_factory(self, get_method):
        """Wraps exception handling around `get_method`."""
        def getter(self, option):
            try:
                return get_method(self.current_section, option)
            except (NoSectionError, NoOptionError), error:
                print 'Error in config file %r,' % self.filename
                print 'section [%s], option %r' % (self.current_section, option)
                print error
                sys.exit(1)
        return getter
Die Parser-Objekte haben auch gleich alle get*()-Methoden, die auch ein ConfigParser hat. Die werden in der __init__() dynamisch erzeugt. Python ist toll. :-)
JC
User
Beiträge: 5
Registriert: Montag 4. April 2005, 20:32

Hui, das mit dem EAFP wusste ich gar nicht...gefällt mir aber irgendwie. :)
Vor allem, weil ich grad an der Uni nen Java-Einführungskurs mache...das ist doch sehr anders.

Hast du zufällig noch mehr Ressourcen, BlackJack? Ich würd mich gern mal informieren was EAFP oder "pythonic style" genau sind.

mfg
JC
BlackJack

EAFP steht ja im genannten Glossar. Ansonsten ist mir keine gesammelte Doku bekannt, die "pythonic" erklärt. Vieles bekommt man in der englischen Newsgroup mit, wo auch ein paar Programmierer aktiv sind, die die Standardbibliothek mit entwickeln und/oder die Distribution zusammenstellen.

Im Python Interpreter ``import this`` eingeben, verrät auch ein wenig filosofisches (schreibt man das jetzt so? :-))
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

BlackJack hat geschrieben:Im Python Interpreter ``import this`` eingeben, verrät auch ein wenig filosofisches (schreibt man das jetzt so? :-))
Nein, ich denke es heißt "philosophisch", aber ich bin eher naturwissenschaftlich veranlagt. *g*
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten