2009-10-30 44 views
17

moje problemy z ConfigParser kontynuować. Wygląda na to, że bardzo dobrze nie obsługuje Unicode. Plik konfiguracyjny jest rzeczywiście zapisany jako UTF-8, ale kiedy odczytuje go program ConfigParser, wydaje się być zakodowany w coś innego. Sądziłem, że to latin-1 i thougt nadrzędnymi optionxform może pomóc:ConfigParser z elementami Unicode

-- configfile.cfg -- 
[rules] 
Häjsan = 3 
☃ = my snowman 

-- myapp.py -- 
# -*- coding: utf-8 -*- 
import ConfigParser 

def _optionxform(s): 
    try: 
     newstr = s.decode('latin-1') 
     newstr = newstr.encode('utf-8') 
     return newstr 
    except Exception, e: 
     print e 

cfg = ConfigParser.ConfigParser() 
cfg.optionxform = _optionxform  
cfg.read("myconfig") 

Oczywiście, kiedy czytam config uzyskać:

'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128) 

Próbowałem kilka różnych odmian dekodowanie, ale punkt wydaje się dyskusyjny, ponieważ od początku powinien być obiektem unicode. W końcu plik konfiguracyjny to UTF-8? Potwierdziłem, że coś jest nie w porządku w sposobie, w jaki program ConfigParser odczytuje plik przez upuszczenie go za pomocą tej klasy DummyConfig. Jeśli tego używam, wszystko jest w porządku, unicode, dobrze i dandy.

-- config.py -- 
# -*- coding: utf-8 -*-     
apa = {'rules': [(u'Häjsan', 3), (u'☃', u'my snowman')]} 

class DummyConfig(object): 
    def sections(self): 
     return apa.keys() 
    def items(self, section): 
     return apa[section] 
    def add_section(self, apa): 
     pass 
    def set(self, *args): 
     pass 

Wszelkie pomysły, które mogą być przyczyną tego lub sugestie innych modułów konfiguracyjnych, które lepiej obsługują Unicode, są mile widziane. Nie chcę używać sys.setdefaultencoding()!

+0

Bałwan nie jest częścią 'latin-1 ' – u0b34a0f6ae

+0

kiedykolwiek Nigdy nie rób' wyjątkiem Exception'; wychwycić faktyczny wyjątek, który wiesz, jak sobie z tym poradzić. –

Odpowiedz

19

Sposób ConfigParser.readfp() może podjąć obiekt pliku, czy próbowałeś otwierając obiekt pliku z prawidłowym kodowaniu za pomocą modułu kodeki przed wysłaniem go do ConfigParser jak poniżej:

cfg.readfp(codecs.open("myconfig", "r", "utf8")) 

dla Pythona 3.2 lub wyżej, readfp() jest przestarzałe. Zamiast tego użyj read_file().

+1

Miałem ten sam problem i rozwiązałem go w ten sam sposób, aby ODCZYTAĆ z pliku konfiguracyjnego. Ale muszę również przepisać zmodyfikowaną wersję, która nie działa, nawet jeśli używam codecs.open: 'with codecs.open (filename, encoding = ENCODING, mode = 'wb') jako conffile: config.write (conffile) ' –

+0

Hi Ghislain, mam ten sam problem z configparser, aby zapisać ciąg znaków Unicode. Został rozwiązany przez zaktualizowanie go do ostatniej wersji za pomocą pip. – Erxin

1

Moduł konfiguracyjny jest uszkodzony podczas odczytu i zapisu łańcuchów unicode jako wartości. Próbowałem to naprawić, ale zostałem złapany w dziwny sposób, w jaki działa parser.

1

Wydaje się być problemem z wersją programu ConfigParser dla Pythona 2x, a wersja dla 3x jest wolna od tego problemu. W this issue of the Python Bug Tracker status jest zamknięty + WONTFIX.

Naprawiłem to edytując plik ConfigParser.py. W metodzie zapisu (około linii 412), należy zmienić:

key = " = ".join((key, str(value).replace('\n', '\n\t'))) 

przez

key = " = ".join((key, str(value).decode('utf-8').replace('\n', '\n\t'))) 

Nie wiem, czy jest to realne rozwiązanie, ale przetestowane w systemie Windows 7 i Ubuntu 15.04, działa jak urok, i mogę dzielić i pracować z tym samym plikiem .ini w obu systemach.

2

Spróbuj zastąpić funkcję write w RawConfigParser() tak:

class ConfigWithCoder(RawConfigParser): 
def write(self, fp): 
    """Write an .ini-format representation of the configuration state.""" 
    if self._defaults: 
     fp.write("[%s]\n" % "DEFAULT") 
     for (key, value) in self._defaults.items(): 
      fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t'))) 
     fp.write("\n") 
    for section in self._sections: 
     fp.write("[%s]\n" % section) 
     for (key, value) in self._sections[section].items(): 
      if key == "__name__": 
       continue 
      if (value is not None) or (self._optcre == self.OPTCRE): 
       if type(value) == unicode: 
        value = ''.join(value).encode('utf-8') 
       else: 
        value = str(value) 
       value = value.replace('\n', '\n\t') 
       key = " = ".join((key, value)) 
      fp.write("%s\n" % (key)) 
     fp.write("\n") 
+0

Możesz także patchować Raw w RawConfigParser: 'RawConfigParser.write = write' –