Configdateien lesen / schreiben

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
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Newbie Frage: Wie kann ich in Python Configdateien lesen / schreiben um z. B. Voreinstellungen dauerhaft zu speichern? Ist mir eigentlich egal, ob das nun einen .INI der eine .XML Datei wird. Obwohl mich XML mehr interessieren würde.

Welche Module / Klassen stehen zur Verfügung?

Hans
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!
hans hat geschrieben:Newbie Frage: Wie kann ich in Python Configdateien lesen / schreiben um z. B. Voreinstellungen dauerhaft zu speichern?
Wenn es Dir nur um Schlüssel/Wert-Paare geht (also ohne diese Sections der ini-Dateien), dann würde ich die Daten einfach in einem Dictionary halten und dieses Dictionary aus einer Datei laden und in ihr speichern. Um Dictionaries (und andere Python-Objekte) einfach speichern/laden zu können, gibt es das Modul "pickle". (Das Vorgehen entspricht der sog. Serialisierung, die bei anderen Sprachen häufig anzutreffen ist.)

Beispiel (ohne ausreichende Fehlerbehandlung):

Code: Alles auswählen

 
import pickle

def configEinlesen():
    try:
        f = open("app.cfg","r")
        dict = pickle.load(f)
        f.close()
        return dict
    except:
        return {}

def configSpeichern(dict):
    f = open("app.cfg","w")
    pickle.dump(dict,f)   
    f.close()
    
dictConfig = configEinlesen()

# "00000" und (100,100) sind default-Werte für den Fall, dass die Schlüssel
# nicht gefunden wurden, z.B. beim allerersten Programmlauf.
print "Die Farbe des Textes: ",dictConfig.get("Textfarbe","000000")
print "Position des Fensters: ",dictConfig.get("Fensterposition",(100,100))

dictConfig["Textfarbe"]="ff00ff"
dictConfig["Fensterposition"]=(300,400)

configSpeichern(dictConfig)
XML mit Python ist sehr interessant (es gibt auch ein OReilly-Buch zum Thema), aber für eine einfache config-Datei halte ich XML für overkill, zumindest wenn die Datei nur von diesem einen Programm gelesen/geschrieben werden können muss.

Jan
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Hi Voges,

Ich war in der Zwischnzeit auch nicht ganz untätig und bin auf ConfigParser gestoßen, jedoch (noch) auf keine vernünftige Doku. Also, ich habe das Teil zum Schreiben ohne Fehlerausgabe bekommen. Nur ich finde keine Datei! (war mit absolutem Pfadnamen angegeben, ~/configfile)

Ich habe eigentlich bei der Programmierung eigentlich immer gelernt, was ma aufmacht, muß man auch wieder schließen. Ich finde aber keinen entsprechenden Befehl in der ConfigParser.
joerg
User
Beiträge: 188
Registriert: Samstag 17. August 2002, 17:48
Wohnort: Berlin
Kontaktdaten:

hans hat geschrieben: Ich war in der Zwischnzeit auch nicht ganz untätig und bin auf ConfigParser gestoßen, jedoch (noch) auf keine vernünftige Doku. Also, ich habe das Teil zum Schreiben ohne Fehlerausgabe bekommen. Nur ich finde keine Datei! (war mit absolutem Pfadnamen angegeben, ~/configfile)
Hallo Hans,
ich hatte mit dem Modul noch keine Probleme. Vielleicht kannst Du mal ein Stück Code reinstellen? Doku ist eigentlich genug am Anfang der Moduldatei (import ConfigParser und
print ConfigParser.__doc__).

Ich hatte mich in einem Projekt für das Modul entschieden, weil es mehrere Abschnitte bietet, Interpolation macht (Einsetzen von Items in andere) und mehrere Files hierarchisch einlesen kann (z.B. userspezifische Einstellungen überschreiben systemweite, wenn man beide Files nacheinander einliest).

Falls Du doch das pickle-Konzept nehmen willst und XML wegen Lesbarkeit: das Gnosis-Paket enthält ein XML-Pickle, das wäre eventuell geeignet.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Etwas Code zum antesten:

Code: Alles auswählen

import sys
import time
import os
import ConfigParser
from qt import *
from NorPyTarGui import *
from os import path

VERSION = '0.1.2 ALPHA'
false   = 0
true    = not false
FN      = ""

class NorPyTar(TNorPyTarGui):
  "Hauptklasse"
  def __init__(self, parent = None,name = None,modal = 0,fl = 0):
    "Constructor"
    TNorPyTarGui.__init__(self, parent, name, fl)
    self.ReadConfig(self.OsPath.expanduser('~/.NorPyTar.conf'))

  ######## save config #######################
  def SaveConfig(self, configFile):
    print 'writing to %s' % configFile
    config = ConfigParser.ConfigParser()
    config.write(configFile)

    if not config.has_section('Main'):
      config.add_section('Main')

    if not config.has_section('Options'):
      config.add_section('Options')

    ## radioButtons
    config.set('Main', 'RadioButtonNumber',    self.btGrpArchive.id)

  ######## read config ##################
  def ReadConfig(self, configFile):
    if not self.OsPath.isfile(configFile):
      return (2)

    config = ConfigParser.ConfigParser()
    config.read(configFile)

    ## radioButtons
    _value = config.get('Main', 'RadioButtonNumber')
    self.btGroupArchieve.setButton(_value);

Mal noch ne ganz blöde Frage: :oops: Wie beendet man im Fehlerfall eine Funktion (ausser mit raise exception......)? Geht das etwa mit return (2) wie in ReadConfig?

Hans
RicmanX
User
Beiträge: 69
Registriert: Donnerstag 29. August 2002, 17:10
Wohnort: Erfurt
Kontaktdaten:

Einfach "return irgendwas". Da es ja "gebe zurück" bedeutet wird in der Funktion nichts weiter gemacht. Am besten ist "return 0" da man damit leicht Abfragen machen kann.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Das kann ja nicht klappen wenn einem da Buggy Code untergeschoben wird (oder ich buggy Aufrufe mache).

Mein Aufruf:

Code: Alles auswählen

!/usr/bin/python
#(C) 2002 by H. G. Normann
#
# NorConfig

import os
import sys
import ConfigParser
from TNorConfigGui import TNorConfig
from qt import *

class Tutor(TNorConfig):
  
  def __init__(self, parent=None, name=None, fl=0):
    TNorConfig.__init__(self,parent,name,fl)
    
  def On_btCloseClick(self):
    Application.quit()

  def On_btReadClick(self):
    config = ConfigParser.ConfigParser(self)
    config.read('NorConfig.ini')
    ######### hier gibts den Fehler ######################
    s = str(config.get('DubiDu', 'Message'))
    #############################################
    edValue.setText(s)

if __name__ == '__main__':
  Application = QApplication(sys.argv)
  QObject.connect(Application,SIGNAL('lastWindowClosed()'),Application,SLOT('quit()'))
  MainWindow = Tutor()
  Application.setMainWidget(MainWindow)
  MainWindow.show()
  Application.exec_loop()
Darauf folgt

Code: Alles auswählen

 ...........
File "/usr/lib/python2.1/ConfigParser.py", Line 277 in get
  d = self.__defaults.copy()
AtrtributeError: copy
Dieser Fehler erreicht mich, wenn ich die Methode ConfigParser.get('BlaBla','StringValue') anwende. Bei ConfigParser.getint() passiert das gleiche.

Bei Suse (7.3) finde ich keinen aktuellere als die eingespielte Python Version (2.1.1-78). Hat jemand eine Idee oder noch besser ne funktionierende Lösung?

Ich schiebe das ganze Projekt mal auf meine HomePage. Ihr könnt das unter http://python.normann-live.de herunterladen. Ist wirklich nur ein ganz kleines Projekt mit QT und Python.

Hans[/url]
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!
hans hat geschrieben:Das kann ja nicht klappen wenn einem da Buggy Code untergeschoben wird (oder ich buggy Aufrufe mache).

Mein Aufruf:

Code: Alles auswählen

config = ConfigParser.ConfigParser(self)
Das self ist da über.

jan[/b]
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Aua, danke Voges, war aber nach Stunden auch selbst darauf gekommen. Das stählt..... :oops:

So, das Einlesen einer Config klappt auch schon. Aber sobald ich die Datei mit write aufmache und was mit set(....) reinschreiben will, sagt die blöde Kiste, dass die Section noch nicht da ist. Da sich Computer ja bekanntlich nie irren, muß ich mal davon ausgehen, dass ich Ihn irgendwo ins Nirvana geschickt habe.

Aber was ist hier falsch?

Code: Alles auswählen

 c := ConfigParser.ConfigParser()
c.write('./NorConfig.ini)
c.set('DubiDu', 'Message', 'Hallo')
Der Fehler tritt nach c.set() auf.

Hans
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Habe noch ein Beispiel gefunden. Quelle: http://www.oreilly.com/catalog/pythonsl ... 05.html#t8

File: configparser-example-2.py

Code: Alles auswählen

import ConfigParser
import sys

config = ConfigParser.ConfigParser()

# set a number of parameters
config.add_section("book")
config.set("book", "title", "the python standard library")
config.set("book", "author", "fredrik lundh")

config.add_section("ematter")
config.set("ematter", "pages", 250)

# write to screen
config.write(sys.stdout)

[book]
title = the python standard library
author = fredrik lundh

[ematter]
pages = 250
Hans
[/url]
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Die Lösung: :P

Code: Alles auswählen

  

def __init__(self,.....)
    self.config = ConfigParser.ConfigParser()
    self.config.read('DeineDatei.conf')

def On_btWriteClick(self):
    s = self.edValue.text()
    self.config.set('DubiDu', 'Message',  s)

    s = str(time.strftime('%d.%m.%Y %H:%M:%S %Z'))
    self.config.set('DubiDu', 'ModiTime', s)

    fd = open('./NorConfig.ini', 'w')
    self.config.write(fd)
    fd.close()


Wenn ich das jetzt richtig interpretiere wird mit self.config.read() die ganze Datei in den Speicer geladen. Mit self.config.get(), self.config.getint(), etc. können die Optionen abgefragt werden.

Mit self.config.set(....) werden die Daten im Speicher verändert. Mit den letzten drei Befehlen des Codes wird dann der Speicher wider auf die HD gebannt.

Hans
Antworten