6

是否有任何解决方案可以强制 RawConfigParser.write() 方法以字母顺序导出配置文件?

即使对原始/加载的配置文件进行了排序,该模块也会任意将部分和选项混合到部分中,手动编辑一个巨大的未排序配置文件真的很烦人。

PD:我正在使用 python 2.6

4

5 回答 5

3

三种解决方案:

  1. 传入一个 dict 类型(构造函数的第二个参数),它以您喜欢的排序顺序返回键。
  2. 扩展类并重载write()(只需从原始源复制此方法并修改它)。
  3. 复制文件 ConfigParser.py 并将排序添加到方法write()中。

请参阅这篇文章以获取有序的字典,或者使用保留原始添加顺序的此实现。

于 2009-12-31T10:08:40.653 回答
2

这是我按字母排序编写配置文件的解决方案:

class OrderedRawConfigParser( ConfigParser.RawConfigParser ):
"""
Overload standart Class ConfigParser.RawConfigParser
"""
def __init__( self, defaults = None, dict_type = dict ):
    ConfigParser.RawConfigParser.__init__( self, defaults = None, dict_type = dict )

def write(self, fp):
    """Write an .ini-format representation of the configuration state."""
    if self._defaults:
        fp.write("[%s]\n" % DEFAULTSECT)
        for key in sorted( self._defaults ):                
            fp.write( "%s = %s\n" % (key, str( self._defaults[ key ] ).replace('\n', '\n\t')) )                 
        fp.write("\n")
    for section in self._sections:
        fp.write("[%s]\n" % section)
        for key in sorted( self._sections[section] ): 
            if key != "__name__":
                fp.write("%s = %s\n" %
                         (key, str( self._sections[section][ key ] ).replace('\n', '\n\t')))    
        fp.write("\n")    
于 2010-10-01T10:08:31.733 回答
2

我可以通过从外部对 ConfigParser 中的部分进行排序来解决这个问题,如下所示:

config = ConfigParser.ConfigParser({}, collections.OrderedDict)
config.read('testfile.ini')
# Order the content of each section alphabetically
for section in config._sections:
    config._sections[section] = collections.OrderedDict(sorted(config._sections[section].items(), key=lambda t: t[0]))

# Order all sections alphabetically
config._sections = collections.OrderedDict(sorted(config._sections.items(), key=lambda t: t[0] ))

# Write ini file to standard output
config.write(sys.stdout)
于 2016-12-20T13:07:14.680 回答
1

第一种方法看起来是最简单、最安全的方法。

但是,在查看 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 不支持正常updatecomparison听写。

解决方法(也重载此功能):

    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 的 reader 功能非常白痴。无论如何,只需要更改一行 - 其他一些用于在外部文件中重载:

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 复制粘贴它

那么总体该怎么做呢?

  1. 从先前建议的链接之一下载 odict.py
  2. 导入它。
  3. 将这些代码复制粘贴到您最喜欢的 utils.py 中(它将OrderedRawConfigParser为您创建类)
  4. cfg = utils.OrderedRawConfigParser(odict.OrderedDict())
  5. 一如既往地使用cfg。它将保持有序。
  6. 坐下来,抽一口哈瓦那,放松一下。

PS3:我在这里解决的问题只在 Python 2.5 中。在 2.6 中已经有一个解决方案。他们在__init__函数中创建了第二个自定义参数,即自定义 dict_type。

因此,仅 2.5 需要此解决方法

于 2010-03-10T16:04:27.273 回答
0

我正在研究将 .gitmodules 与超级模块合并进行子树合并的问题——一开始就非常困惑,并且子模块的不同顺序已经足够令人困惑了,哈哈。

使用 GitPython 帮助很大:

from collections import OrderedDict
import git

filePath = '/tmp/git.config'
# Could use SubmoduleConfigParser to get fancier
c = git.GitConfigParser(filePath, False)
c.sections()
# http://stackoverflow.com/questions/8031418/how-to-sort-ordereddict-in-ordereddict-python
c._sections = OrderedDict(sorted(c._sections.iteritems(), key=lambda x: x[0]))
c.write()
del c
于 2013-05-12T00:51:30.630 回答