# Written by John Hoffman # see LICENSE.txt for license information ''' reads/writes a Windows-style INI file format: aa = "bb" cc = 11 [eee] ff = "gg" decodes to: d = { 'default': {'aa':'bb','cc':'11'}, 'eee': {'ff':'gg'} } the encoder can also take this as input: d = { 'aa': 'bb, 'cc': 11, 'eee': {'ff':'gg'} } though it will only decode in the above format. Keywords must be strings. Values that are strings are written surrounded by quotes, and the decoding routine automatically strips any. Booleans are written as integers. Anything else aside from string/int/float may have unpredictable results. ''' from cStringIO import StringIO from traceback import print_exc from types import DictType, StringType try: from types import BooleanType except ImportError: BooleanType = None try: True except: True = 1 False = 0 DEBUG = False def ini_write(f, d, comment=''): try: a = {'default':{}} for k,v in d.items(): assert type(k) == StringType k = k.lower() if type(v) == DictType: if DEBUG: print 'new section:' +k if k: assert not a.has_key(k) a[k] = {} aa = a[k] for kk,vv in v: assert type(kk) == StringType kk = kk.lower() assert not aa.has_key(kk) if type(vv) == BooleanType: vv = int(vv) if type(vv) == StringType: vv = '"'+vv+'"' aa[kk] = str(vv) if DEBUG: print 'a['+k+']['+kk+'] = '+str(vv) else: aa = a[''] assert not aa.has_key(k) if type(v) == BooleanType: v = int(v) if type(v) == StringType: v = '"'+v+'"' aa[k] = str(v) if DEBUG: print 'a[\'\']['+k+'] = '+str(v) r = open(f,'w') if comment: for c in comment.split('\n'): r.write('# '+c+'\n') r.write('\n') l = a.keys() l.sort() for k in l: if k: r.write('\n['+k+']\n') aa = a[k] ll = aa.keys() ll.sort() for kk in ll: r.write(kk+' = '+aa[kk]+'\n') success = True except: if DEBUG: print_exc() success = False try: r.close() except: pass return success if DEBUG: def errfunc(lineno, line, err): print '('+str(lineno)+') '+err+': '+line else: errfunc = lambda lineno, line, err: None def ini_read(f, errfunc = errfunc): try: r = open(f,'r') ll = r.readlines() d = {} dd = {'default':d} for i in xrange(len(ll)): l = ll[i] l = l.strip() if not l: continue if l[0] == '#': continue if l[0] == '[': if l[-1] != ']': errfunc(i,l,'syntax error') continue l1 = l[1:-1].strip().lower() if not l1: errfunc(i,l,'syntax error') continue if dd.has_key(l1): errfunc(i,l,'duplicate section') d = dd[l1] continue d = {} dd[l1] = d continue try: k,v = l.split('=',1) except: try: k,v = l.split(':',1) except: errfunc(i,l,'syntax error') continue k = k.strip().lower() v = v.strip() if len(v) > 1 and ( (v[0] == '"' and v[-1] == '"') or (v[0] == "'" and v[-1] == "'") ): v = v[1:-1] if not k: errfunc(i,l,'syntax error') continue if d.has_key(k): errfunc(i,l,'duplicate entry') continue d[k] = v if DEBUG: print dd except: if DEBUG: print_exc() dd = None try: r.close() except: pass return dd if __name__ == '__main__': config_file = "./config.conf" import os if os.path.isfile(config_file): dd = ini_read(config_file) print dd