ActiveState Code

Recipe 65334: Use good old INI files for configuration


Many people use Python modules as config files, but this way your program may be manipulated or an syntax error may come into that file. Try the small script here to use the good old INI config files, known from Windows.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import ConfigParser
import string

_ConfigDefault = {
    "database.dbms":            "mysql",
    "database.name":            "",
    "database.user":            "root",
    "database.password":        "",
    "database.host":            "127.0.0.1"
    }

def LoadConfig(file, config={}):
    """
    returns a dictionary with key's of the form
    <section>.<option> and the values 
    """
    config = config.copy()
    cp = ConfigParser.ConfigParser()
    cp.read(file)
    for sec in cp.sections():
        name = string.lower(sec)
        for opt in cp.options(sec):
            config[name + "." + string.lower(opt)] = string.strip(cp.get(sec, opt))
    return config

if __name__=="__main__":
    print LoadConfig("some.ini", _ConfigDefault)

Discussion

This solution is just for reading config files. A write should be easy to be implemented. An INI file looks like this: <pre> [database] user = dummy password = tosca123 </pre> The defaults may be set in advance. The keys of the dictionary are always lower case, that helps ;-)

Comments

  1. 1. At 5:28 a.m. on 9 mar 2002, Dave Primmer said:

    the writer... At first I saw this and said, "why concatenate the section and option?" seems like extra string processing right? it makes the write function harder i think. but once you get your dictionary, the values are easy to reference in your code.

    here's the write function. i'm a newbie so it's probably not very tight code.

    def write(self, file, config):
        """
        given a dictionary with key's of the form 'section.option: value'
        write() generates a list of unique section names
        creates sections based that list
        use config.set to add entries to each section
            """
        f= open(file,'w')
        cp = ConfigParser.ConfigParser()
        #a little string hacking because our section names are un-normalized
        #this builds a list of all the sections names
        sectionslst = []
        sections = []
        for k in config.keys():
            sectionslst.append(string.split(k,".")[0])
        #get unique entries
        sections = uniquer(sectionslst)
        for sec in sections:
            #make the headers
            cp.add_section(sec)
            #for each item in my dictionary
            #it splits the key in two and uses that for the first and second "set" args
            #then it uses the item.value for the 3rd arg
            # from 'section.option:value'
        for k in config.items():
            cp.set(string.split(k[0],".")[0],string.split(k[0],".")[1] ,k[1] )
        cp.write(f)
        f.close()
    
    def uniquer(seq, idfun=None):
        if idfun is None:
            def idfun(x): return x
        seen = {}
        result = []
        for item in seq:
            marker = idfun(item)
            if marker in seen: continue
            seen[marker] = 1
            result.append(item)
        return result
    
  2. 2. At 3:52 p.m. on 29 jan 2007, James Stroud said:

    An updated a tighter write(). This updates the write() function for python > 2.4 and makes it tighter and a little easier to understand.

    Also, sets eliminate the need for uniquer().

    def write(self, filename, config):
        """
        given a dictionary with key's of the form 'section.option: value'
        write() generates a list of unique section names
        creates sections based that list
        use config.set to add entries to each section
        """
        cp = ConfigParser.ConfigParser()
        sections = set([k.split('.')[0] for k in config.keys()])
        map(cp.add_section, sections)
        for k,v in config.items():
            s, o = k.split('.')
            cp.set(s, o, v)
        cp.write(open(filename, "w"))
    

Sign in to comment