Там какое-либо решение состоит в том, чтобы вынудить RawConfigParser.write () метод экспортировать файл конфигурации с алфавитным видом?
Даже если исходный/загруженный файл конфигурации отсортирован, модуль смешивает раздел и опции в разделы произвольно, и является действительно раздражающим для редактирования вручную огромного неотсортированного файла конфигурации.
PD: я использую python 2.6
Три решения:
write()
(просто скопируйте этот метод из исходного кода и модифицируйте его). write()
.Смотрите эту статью для упорядоченного диктата или, может быть, используйте эту реализацию , которая сохраняет исходный порядок добавления.
.Первый способ выглядел как наиболее простой и безопасный.
Но, посмотрев исходный код ConfigParser, он создает пустой встроенный dict, а затем копирует все значения из «второго параметра» одно за другим. Это означает, что он не будет использовать тип OrderedDict. Легким решением может быть перегрузка класса CreateParser.
class OrderedRawConfigParser(ConfigParser.RawConfigParser):
def __init__(self, defaults=None):
self._defaults = type(defaults)() ## will be correct with all type of dict.
self._sections = type(defaults)()
if defaults:
for key, value in defaults.items():
self._defaults[self.optionxform(key)] = value
Остается только один недостаток ... а именно в ConfigParser.items (). odict не поддерживает обновление
и сравнение
с обычными dicts.
Обходной путь (перегрузите и эту функцию):
def items(self, section):
try:
d2 = self._sections[section]
except KeyError:
if section != DEFAULTSECT:
raise NoSectionError(section)
d2 = type(self._section)() ## Originally: d2 = {}
d = self._defaults.copy()
d.update(d2) ## No more unsupported dict-odict incompatibility here.
if "__name__" in d:
del d["__name__"]
return d.items()
Другим решением проблемы с элементами является изменение функции odict.OrderedDict.update
- возможно, это проще, чем эта, но я оставляю ее тебе.
PS: Я реализовал это решение, но оно не работает. Если я выясню, что ConfigParser все еще смешивает порядок записей, я сообщу об этом.
PS2: Решено. Функция чтения в ConfigParser - идиот. В любом случае, нужно было изменить только одну строку - и некоторые другие для перегрузки во внешний файл:
def _read(self, fp, fpname):
cursect = None
optname = None
lineno = 0
e = None
while True:
line = fp.readline()
if not line:
break
lineno = lineno + 1
if line.strip() == '' or line[0] in '#;':
continue
if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
continue
if line[0].isspace() and cursect is not None and optname:
value = line.strip()
if value:
cursect[optname] = "%s\n%s" % (cursect[optname], value)
else:
mo = self.SECTCRE.match(line)
if mo:
sectname = mo.group('header')
if sectname in self._sections:
cursect = self._sections[sectname]
## Add ConfigParser for external overloading
elif sectname == ConfigParser.DEFAULTSECT:
cursect = self._defaults
else:
## The tiny single modification needed
cursect = type(self._sections)() ## cursect = {'__name__':sectname}
cursect['__name__'] = sectname
self._sections[sectname] = cursect
optname = None
elif cursect is None:
raise ConfigParser.MissingSectionHeaderError(fpname, lineno, line)
## Add ConfigParser for external overloading.
else:
mo = self.OPTCRE.match(line)
if mo:
optname, vi, optval = mo.group('option', 'vi', 'value')
if vi in ('=', ':') and ';' in optval:
pos = optval.find(';')
if pos != -1 and optval[pos-1].isspace():
optval = optval[:pos]
optval = optval.strip()
if optval == '""':
optval = ''
optname = self.optionxform(optname.rstrip())
cursect[optname] = optval
else:
if not e:
e = ConfigParser.ParsingError(fpname)
## Add ConfigParser for external overloading
e.append(lineno, repr(line))
if e:
raise e
Поверьте мне, я не писал эту вещь. Я скопировал его полностью из ConfigParser.py
Итак, что в целом делать?
OrderedRawConfigParser
) cfg = utils.OrderedRawConfigParser (odict.OrderedDict ())
PS3: Проблема, которую я решил здесь, есть только в Python 2.5. В версии 2.6 для этого уже есть решение. Они создали второй специальный параметр в функции __ init __
, который является настраиваемым dict_type.
Таким образом, этот обходной путь требуется только для версии 2.5