ConfigParser: Wie setzt man Default-Werte?

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.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Hallo zusammen,

ich möchte eigentlich nur mittels des ConfigParser's eine INI-Datei einlesen - allerdings muss gewährleistet sein, dass fehlende Keys bzw. Sections per Default hinterlegt sind.

Mein Code sieht also zB so aus:
INI-Datei
[CONF]
LOG_LEVEL=1

Python-Programm:

Code: Alles auswählen

import ConfigParser

config = ConfigParser.ConfigParser()
config.read(['test.conf'])
print config.get('CONF', 'LOG_LEVEL')
print config.get('CONF', 'ACT_VALUE')
Der Key 'ACT_VALUE' befindet sich nun gar nicht im INI-File. Gibt es eine Möglichkeit im Python-Programm Defaults für so etwas zu hinterlegen?

CU,
API
querdenker
User
Beiträge: 424
Registriert: Montag 28. Juli 2003, 16:19
Wohnort: /dev/reality

Vorschlag: Wert aus dem Config-File abfragen -> wenn der nicht da ist, sollte es eine Exception geben. Auf die kannst du dann mit einem config.set(...) reagieren.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Hallo querdenker,

dass mit ner Exception abzufangen wäre zwar ne Möglichkeit, aber da ich zig Keys/Values in dieser INI-Datei stehen habe (Beispiel ist nur ein Auszug), müsste ich das dann für jeden Wert seperat machen.

Gibt es da noch andere Möglichkeiten?

CU,
API
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Code: Alles auswählen

import ConfigParser as cfgp
class Config(cfgp.ConfigParser):
    def get(self, section, option, default=None, **kwargs):
        if default is None:
            return cfgp.ConfigParser.get(self, section, option, **kwargs)
        try:
            return cfgp.ConfigParser.get(self, section, option, **kwargs)
        except cfgp.NoOptionError:
            return default
Du könntest auch ein dict nehmen und dort den Standard Wert nachschlagen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wenn ich das richtig sehe unterstützt ConfigObj von sich aus Defaults. Und hat auch ein paar andere Vorteile gegenüber configparser.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Moin,

nicht so kompliziert, bitte. In der Doku zum ConfigParser steht, wie man default-Werte festlegt:

Code: Alles auswählen

import ConfigParser

# New instance with 'bar' and 'baz' defaulting to 'Life' and 'hard' each
config = ConfigParser.SafeConfigParser({'bar': 'Life', 'baz': 'hard'})
config.read('example.cfg')

print config.get('Section1', 'foo') # -> "Python is fun!"
config.remove_option('Section1', 'bar')
config.remove_option('Section1', 'baz')
print config.get('Section1', 'foo') # -> "Life is hard!"
Gruß,
Manuel
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Hallo Manuel,

wenn ich bei meinem obigen Beispiel bleibe, bekomme ich mit folgendem Python-Code diese Fehlermeldung:

Code: Alles auswählen

import ConfigParser

config = ConfigParser.SafeConfigParser({'ACT_VALUE':'100'})
config.read(['test.conf'])
print config.get('CONF', 'LOG_LEVEL')
print config.get('CONF', 'ACT_VALUE')

1
Traceback (most recent call last):
  File "tt.py", line 8, in ?
    print config.get('CONF', 'ACT_VALUE')
  File "/usr/sfw/lib/python2.3/ConfigParser.py", line 513, in get
    raise NoOptionError(option, section)
ConfigParser.NoOptionError: No option 'act_value' in section: 'CONF'
Was ist da noch falsch?

CU,
API
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Guck doch mal, was Dir

Code: Alles auswählen

config.defaults()
ausgibt!

Ich wette da findest Du das ACT_VALUE!

So wie ich das verstanden habe, kann man nur default Werte übergeben, die in keiner Section stehen, also global gültig sind! Das ist bei Dir ja nicht der Fall. (Was helduel mal nicht gesagt hat ;-) )

Außer man kann das dict so erweitern, dass man die Section mit angeben kann, etwa:

Code: Alles auswählen

config = ConfigParser.SafeConfigParser({'CONF':{'ACT_VALUE':'100'}})
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Wenn ich das so erweitere, bekomme ich folgende Ausgabe:

Code: Alles auswählen

import ConfigParser

config = ConfigParser.SafeConfigParser({'CONF':{'ACT_VALUE':'100'}})
config.read(['test.conf'])
print config.get('CONF', 'LOG_LEVEL')
print config.defaults()
print config.get('CONF', 'ACT_VALUE')

{'CONF': {'ACT_VALUE': '100'}}
Traceback (most recent call last):
  File "tt.py", line 9, in ?
    print config.get('CONF', 'ACT_VALUE')
  File "/usr/sfw/lib/python2.3/ConfigParser.py", line 513, in get
    raise NoOptionError(option, section)
ConfigParser.NoOptionError: No option 'act_value' in section: 'CONF'
Die Frage ist jetzt nur, was ich mit dieser Info anfangen kann...

CU,
API
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

api hat geschrieben: Die Frage ist jetzt nur, was ich mit dieser Info anfangen kann...
Nicht viel, weil Du meine Mutmaßung einfach so übernommen hast! Probiere es doch einmal ohne das verschachtelete dict!

Code: Alles auswählen

In [5]: config = ConfigParser.SafeConfigParser({'ACT_VALUE':'100'})

In [6]: print config
<ConfigParser.SafeConfigParser instance at 0x912810c>

In [7]: print config.defaults()
{'act_value': '100'}

In [8]: print config.sections()
[]
Schau Dir das einfach an!
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Eine wirklich gute Idee!!! :D

Ich habe das jetzt mal folgendermaßen gelöst:

Code: Alles auswählen

import ConfigParser

config = ConfigParser.SafeConfigParser({'ACT_VALUE':'100', 'LOG_LEVEL':'3'})
config.read(['test.conf'])

def SetValue (sv_section, sv_key):

  try:
    value = config.get(sv_section, sv_key)

  except:
    value = config.defaults()[sv_key]

  return value


ActValue = SetValue ('CONF', 'ACT_VALUE')
LogLevel = SetValue ('CONF', 'LOG_LEVEL')

print "ActValue: %s" % ActValue
print "LogLevel: %s" % LogLevel
...und das ergibt...

Code: Alles auswählen

ActValue: 100
LogLevel: 1
Das ist genau das, was ich mir vorgestellt habe... Danke für die Hilfe!! :D

CU,
API
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Das ist keine Lösung dass ist ein Verbrechen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Warum benutzt du überhaupt den Abschnitt `CONF' in einer Konfigurationsdatei? Reicht es nicht wenn die schlicht und einfach Top-Level sind?
BlackJack

@cofi: Der ConfigParser will zwingend mindestens einen benannten Abschnitt in der Konfigurationsdatei haben.
lunar

Dann wäre ConfigObj vielleicht doch eine Option, da es auch Konfigurationsdateien ohne Abschnitte parsen kann.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

@api: Wäre interessant, wie deine Config aussieht. Bei mir hier funzt alles, wie erwartet:

foo.conf

Code: Alles auswählen

[main]
foo=xxx

[blubber]
bar=yyy
test.py

Code: Alles auswählen

from ConfigParser import SafeConfigParser

config = SafeConfigParser({"foo": "123", "bar": "456", "baz": "789"})
config.read("foo.conf")

print "main", config.get("main", "foo")
print "main", config.get("main", "bar")
print "main", config.get("main", "baz")

print "blubber", config.get("blubber", "bar")
print "blubber", config.get("blubber", "baz")
Ausgabe

Code: Alles auswählen

main xxx
main 456
main 789
blubber yyy
blubber 789
Gruß,
Manuel
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@helduel: Ich habe das mal ausprobiert und mich wirklich gefragt, warum ich das wie oben beschrieben realisiert habe... Dann hab ich das nach deiner Lösung umgesetzt - und du hast recht: Das ist ja viel einfacher und übersichtlicher. Das Problem bei mir war die Config-Datei. Sie hatte folgendes Aussehen:

Code: Alles auswählen

[CONF] 
LOG_LEVEL=1 
Mit den großen Buchstaben funzt das aber nicht und wirft eben eine Fehlermeldung... :(

Wenn ich die Config-Datei so umsetze:

Code: Alles auswählen

[CONF] 
log_level=1 
und alle anderen Keys ebenfalls in Kleinbuchstaben, dann ist alles wie erwartet...

Na, wunderbar... :D

CU,
API
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@DasIch: Mich würde mal interessieren, warum du diese "Lösung" als Verbrechen! bezeichnest. Könntest du diese Aussage mal konkretisieren, denn mit mit diesem Statement alleine kann ich nun aber auch gar nichts anfangen. :(
Ich bin ja gerne bereit, andere Lösungsvorschläge zu akzeptieren, aber etwas detaillierter würde schon etwas mehr dazu beitragen...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ich nehme mal an dass du die Funktionen konsequent falsch beannt hast und weil du alle Exceptions schluckst, was schlichtweg schädlich ist, da du so auch Exceptions fängst die du eigentlich gar nicht fangen wolltest.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@Leonidas: Mit den Exceptions gebe ich dir recht. Das alles mit einer einzigen abzufackeln ist nicht wirklich sauber. Aber ich habe das als Beispiel angesehen und in der realen Lösung hätten da nicht nur ein paar mehr sondern auch eindeutigere Exceptions gestanden.
Es ging mir in diesem Augenblick mehr um das Handling mit dem ConfigParser.

Aber was mich dann doch interessieren würde, was du mit konsequenter Falschbenennung von Funktionen meinst? Was mache ich da falsch? Nenn mir doch bitte mal ein Beispiel und wenn möglich dann gleich auch wie es richtig sein müsste...

CU,
API
Antworten