2009-12-31 70 views
6

是否有解決方案強制RawConfigParser.write()方法導出按字母排序的配置文件?導出在Python中按字母順序排序ConfigParser

即使對原始/加載的配置文件進行排序,模塊也會將段落和選項任意混合到段中,而且真的很煩人手動編輯一個巨大的未排序配置文件。

PD:我使用python 2.6

回答

3

三種解決方案:

  1. 傳遞一個字典類型(第二個參數的構造函數)返回在您的首選排序順序按鍵。
  2. 擴展類和重載write()(只需從原始源複製此方法並對其進行修改)。
  3. 複製ConfigParser.py文件並將排序添加到方法write()

請參閱this article對於有序字典或可能使用this implementation保留原始添加順序。

+0

請參閱我的答案是第四個,工作,解決方案。 –

1

第一種方法看起來是最簡單,最安全的方法。

但是,在查看ConfigParser的源代碼之後,它會創建一個空的內置字典,然後從「第二個參數」一個接一個地複製所有值。這意味着它不會使用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的閱讀器功能相當笨蛋。總之,只有一行,就必須改變 - 和其他一些人在一個外部文件超載:

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. 坐下來,抽出一個havanna,放鬆一下。

PS3:我在這裏解決的問題只在Python 2.5中。在2.6中已經有了一個解決方案。他們在__init__函數中創建了第二個自定義參數,這是一個自定義的dict_type。

所以才需要這個解決方法2.5

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

有幫助,但未定義DEFAULTSECT。並將「排序(self._sections)」部分:「 –

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 
0

我能夠從外部排序在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) 
+0

雖然這個工程,這有缺點,從'testfile.ini'的順序不會保留。 –

+0

這是正確的。我的解決方案按字母順序排列各個部分,並且在每個部分中,所有的鍵都按字母順序排序如果您只想保留原來的順序,那麼只需要解決方案的前兩行。 –