2013-04-06 3 views
11

Ich muss die ConfigParser verwenden können, um mehrere Werte für den gleichen Schlüssel zu lesen. Beispiel Konfigurationsdatei:Wie konfiguriere ich eine Datei mit mehreren Werten für identische Schlüssel?

[test] 
foo = value1 
foo = value2 
xxx = yyy 

Mit der ‚Standard‘ Verwendung von ConfigParser wird es value2 ein Schlüssel foo mit dem Wert sein. Aber ich brauche den Parser, um beide Werte zu lesen.

ein entry on duplicate key Nach mir den folgenden Beispielcode erstellt habe:

from collections import OrderedDict 
from ConfigParser import RawConfigParser 

class OrderedMultisetDict(OrderedDict): 
    def __setitem__(self, key, value): 

     try: 
      item = self.__getitem__(key) 
     except KeyError: 
      super(OrderedMultisetDict, self).__setitem__(key, value) 
      return 

     print "item: ", item, value 
     if isinstance(value, list): 
      item.extend(value) 
     else: 
      item.append(value) 
     super(OrderedMultisetDict, self).__setitem__(key, item) 


config = RawConfigParser(dict_type = OrderedDict) 
config.read(["test.cfg"]) 
print config.get("test", "foo") 
print config.get("test", "xxx") 

config2 = RawConfigParser(dict_type = OrderedMultisetDict) 
config2.read(["test.cfg"]) 
print config2.get("test", "foo") 
print config.get("test", "xxx") 

Den ersten Teil (mit config) liest in der Config uns ‚normalen‘, Datei nur value2 als Wert für foo verlassen (Überschreiben/den anderen Wert zu löschen) und ich die folgende, erwartete Ausgabe:

value2 
yyy 

Der zweite Teil (config2) verwendet mein Ansatz mehrere Werte an einen li anhängen st, aber die Ausgabe ist stattdessen

['value1', 'value2', 'value1\nvalue2'] 
['yyy', 'yyy'] 

Wie werde ich die sich wiederholenden Werte loswerden? Ich erwarte eine Ausgabe wie folgt:

['value1', 'value2'] 
yyy 

oder

['value1', 'value2'] 
['yyy'] 

(Ich habe nichts dagegen, wenn jeder Wert in einer Liste ist ...). Irgendwelche Vorschläge willkommen.

Antwort

11

Nach einer kleinen Änderung, ich war in der Lage zu erreichen, was Sie wollen:

class MultiOrderedDict(OrderedDict): 
    def __setitem__(self, key, value): 
     if isinstance(value, list) and key in self: 
      self[key].extend(value) 
     else: 
      super(MultiOrderedDict, self).__setitem__(key, value) 
      # super().__setitem__(key, value) in Python 3 

config = ConfigParser.RawConfigParser(dict_type=MultiOrderedDict) 
config.read(['a.txt']) 
print config.get("test", "foo") 
print config.get("test", "xxx") 

Ausgänge:

['value1', 'value2'] 
['yyy'] 
+0

Ich habe keine Ahnung, warum 'Super (OrderedDict, selbst)' funktioniert, aber nicht 'Super (MultiOrderedDict, selbst) '. –

+0

Ja, perfekt! Außer der "Super" Anomalie. Vielleicht ist es * die Basisklasse von 'OrderedDict' dann ... – Alex

+0

Gibt es eine Möglichkeit, dass ein einzelner Wert anstelle einer Liste zurückgegeben wird, wenn es nur einen Wert gibt? ['value1', 'value2'] und yyy anstelle von ['yyy'] –

-3

Weitere Beispiele Mehrere Werte in test.cfg.

[test] 
foo = value1 
foo = value2 
value3 
xxx = yyy 

<whitespace>value3 append value3 Liste foo.

ConfigParser konvertiert die Liste in eine Zeichenfolge.

/usr/lib/python2.7/ConfigParser.pyc in _read(self, fp, fpname) 
    552    for name, val in options.items(): 
    553     if isinstance(val, list): 
--> 554      options[name] = '\n'.join(val) 
    555 

value vor der Konvertierung ist immer Liste oder dict (MultiOrderedDict).

die Sie interessieren - mit ihm, config.items Werke:

from collections import OrderedDict 
import ConfigParser 

class MultiOrderedDict(OrderedDict): 
    def __setitem__(self, key, value): 
     if key in self: 
      if isinstance(value, list): 
       self[key].extend(value) 
       return 
      elif isinstance(value,str): 
       return # ignore conversion list to string (line 554) 
     super(MultiOrderedDict, self).__setitem__(key, value) 

config = ConfigParser.RawConfigParser(dict_type=MultiOrderedDict) 
config.read(['test.cfg']) 
print config.get("test", "foo") 
print config.get("test", "xxx") 
print config.items("test") 

Ausgänge:

['value1', 'value2', 'value3'] 
['yyy'] 
[('foo', ['value1', 'value2', 'value3']), ('xxx', ['yyy'])] 

eine weitere Implementierung MultiOrderedDict

class MultiOrderedDict(OrderedDict): 
    def __setitem__(self, key, value): 
     if key in self: 
      if isinstance(value, list): 
       self[key].extend(value) 
       return 
      elif isinstance(value,str): 
       if len(self[key])>1: 
        return 
     super(MultiOrderedDict, self).__setitem__(key, value) 

Ausgänge:

['value1', 'value2', 'value3'] 
yyy 
[('foo', ['value1', 'value2', 'value3']), ('xxx', 'yyy')] 
0

Nur ein kleines bisschen zu @abarnert's answer ändern, sonst ruft es __setitem__ rekursiv, und wird nicht aus irgendeinem Grund zu stoppen.

ini-Datei:

[section] 
key1 = value1 
key2[] = value21 
key2[] = value22 

Python:

class MultiOrderedDict(OrderedDict): 
    LIST_SUFFIX = '[]' 
    LIST_SUFFIX_LEN = len(LIST_SUFFIX) 

    def __setitem__(self, key, value): 
     if key.endswith(self.LIST_SUFFIX): 
      values = super(OrderedDict, self).setdefault(key, []) 
      if isinstance(value, list): 
       values.extend(value) 
      else: 
       values.append(value) 
     else: 
      super(MultiOrderedDict, self).__setitem__(key, value) 

    def __getitem__(self, key): 
     value = super(MultiOrderedDict, self).__getitem__(key) 
     if key.endswith(self.LIST_SUFFIX) and not isinstance(value, list): 
      value = value.split('\n') 
     return value 

Test:

def test_ini(self): 
    dir_path = os.path.dirname(os.path.realpath(__file__)) 
    config = RawConfigParser(dict_type=MultiOrderedDict, strict=False) 
    config.readfp(codecs.open('{}/../config/sample.ini'.format(dir_path), encoding="utf_8_sig")) 
    self.assertEquals(config.get("section1", "key1"), 'value1') 
    self.assertEquals(config.get("section1", "key2[]"), ['value21', 'value22']) 
1

Die akzeptierte Antwort bricht config.sections(), es gibt immer eine leere Liste (getestet mit Python 3.5. 3). Ersetzen super(OrderedDict, self).__setitem__(key, value) von super().__setitem__(key, value) behebt dies, aber jetzt config.get(section, key) gibt eine verkettete Zeichenfolge, nicht mehr eine Liste der Zeichenfolgen.

Meine Lösung ist:

class ConfigParserMultiValues(collections.OrderedDict): 

    def __setitem__(self, key, value): 
     if key in self and isinstance(value, list): 
      self[key].extend(value) 
     else: 
      super().__setitem__(key, value) 

    @staticmethod 
    def getlist(value): 
     return value.split(os.linesep) 

    config = configparser.ConfigParser(strict=False, empty_lines_in_values=False, dict_type=ConfigParserMultiValues, converters={"list": ConfigParserMultiValues.getlist}) 
    ... 
    values = config.getlist("Section", "key") # => ["value1", "value2"] 

Die config-INI-Datei Nachschlüssel akzeptiert:

[Section] 
    key = value1 
    key = value2 
+0

Ich habe den falschen super() -Aufruf in der akzeptierten Antwort und in den Abschnitten() funktioniert jetzt. – bernie

Verwandte Themen