2013-04-06 12 views
11

Potrzebuję móc korzystać z ConfigParser, aby odczytać wiele wartości dla tego samego klucza. Przykładowy plik konfiguracyjny:Jak skonfigurowaćParse plik zachowując wiele wartości dla identycznych kluczy?

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

z „standardowego” używania ConfigParser będzie jeden klucz foo z wartością value2. Ale potrzebuję analizatora składni do odczytu w obu wartościach.

następstwie entry on duplicate key stworzyłem następujący przykładowy kod:

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") 

pierwsza część (z config) czyta w config file nas „zwykły”, pozostawiając tylko value2 jako wartość dla foo (nadpisywanie/usuwając inną wartość) i pojawia się następujący, oczekiwany wynik:

value2 
yyy 

druga część (config2) wykorzystuje moje podejście do dołączania wielu wartości do li st, ale zamiast tego wyjściowym jest

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

Jak pozbyć się powtarzających się wartości? Oczekuję wyjście następująco:

['value1', 'value2'] 
yyy 

lub

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

(nie mam nic przeciwko, jeśli każda wartość jest na liście ...). Wszelkie sugestie mile widziane.

Odpowiedz

11

Po niewielkiej modyfikacji, udało mi się osiągnąć to, co chcesz:

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") 

Wyjścia:

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

nie mam pojęcia dlaczego 'Super (OrderedDict, self)' działa, ale nie 'Super (MultiOrderedDict, samo) ". –

+0

Tak, idealnie! Z wyjątkiem anomalii "super". Może to * jest * podstawową klasą 'OrderedDict', a następnie ... – Alex

+0

Czy istnieje sposób na zwrócenie pojedynczej wartości zamiast listy, gdy istnieje tylko jedna wartość? ['value1', 'value2'] i yyy zamiast ['yy '] –

-3

więcej przykładów wielu wartości w test.cfg.

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

<whitespace>value3 Dołącz value3 do listy foo.

Konwertuje listę na ciąg.

/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 przed konwersją zawsze listy lub DICT (MultiOrderedDict).

Spróbuj tego - z tym, config.items prace:

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") 

Wyjścia:

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

Another realizację 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) 

Wyjścia:

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

Po prostu niewielka zmiana na @abarnert's answer, w przeciwnym razie wywołuje __setitem__ rekurencyjnie i nie zatrzyma się z jakiegoś powodu.

ini:

[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

Zaakceptowanych odpowiedź łamie config.sections(), zwraca zawsze pustą listę (testowane z Pythona 3.5. 3). Zastąpienie super(OrderedDict, self).__setitem__(key, value) przez super().__setitem__(key, value) rozwiązuje ten problem, ale teraz config.get(section, key) zwraca połączony ciąg znaków, który nie jest już listą ciągów.

Moje rozwiązanie to:

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"] 

config plik INI akceptuje zduplikowane klucze:

[Section] 
    key = value1 
    key = value2 
+0

Naprawiłem złe połączenie super() w zaakceptowanej odpowiedzi i sekcjach() teraz działa. – bernie

Powiązane problemy