Thursday, October 25, 2012

Reading ini file into a dictionary in python

Configuration Reader

Python's ConfigParser lets users read configuration files.
[TestA]
package = None
class = A
method = test
We can read the items in the configuration file to be accessed as a dictionary.
a['TestA']['package']
In order to do that, we need a method to do that.
import ConfigParser

class MyParser(ConfigParser.ConfigParser):
    def as_dict(self):
        d = dict(self._sections)
        for k in d:
            d[k] = dict(self._defaults, **d[k])
            d[k].pop('__name__', None)
        return d
This is how one can use this code.
if __name__ == "__main__":
    f = MyParser()
    f.read("/DIRECTORY_TO/setup.ini")
    d = f.as_dict()
    print d
    print d['TestA']['class']
You'll get the result.
{'TestA': {'package': 'None', 'method': 'test', 'class': 'A'}}
A

Analysis of the code

If you are not familiar with python dictionary, you can check this post. When the ini file is read into ConfigParser object, all the information is already in the dictionary.
config = ConfigParser.RawConfigParser()
config.read(PATH)
In config, you have all the items in dictionary, the issue is that you can't use it as is.
print f._sections
OrderedDict( # <-- Ordered Dictionary
  [ # <-- List of tuples : string and OrderedDict 
     ('TestA', 
       OrderedDict(
         # The first item in the list is not necessary, so pop it off
         [('__name__', 'TestA'), ('package', 'None'), ('class', 'A'), ('method', 'test')]
       )
     )
  ]
)
The default data structure is OrderedDict, if you need more about OrderedDict, you can check this post. for k in d:, the k holds the section name ('TestA'), and it only iterates once as there is only one sections. When you run this code, you'll get the OrderedDictionary(), but you don't need the first element which is the name of the section.
for k in d: print d[k]
OrderedDict([('__name__', 'TestA'), ('package', 'None'), ('class', 'A'), ('method', 'test')])
The next code creates a dictionary based on _defaults OrderedDict().
d[k] = dict(self._defaults, **d[k])
print f._defaults
OrderedDict()
And for the **d[k], it means that d[k] (dictionary) is decomposed into assignments. This is necessary as the dict() method requires assignments as additional parameters to the method.
def hello(**a):
    print a
    
a = dict([['a',10],['b',20]])
print a
hello(**a)
{'a': 10, 'b': 20}
{'a': 10, 'b': 20}
You'll get d[k] as follows:
{'__name__': 'TestA', 'package': 'None', 'method': 'test', 'class': 'A'}
Finally, you should pop up the ('__name__': 'TestA')
d[k].pop('__name__', None)
This is explanation for the pop() method. Screen Shot 2012 10 25 at 4 17 02 PM

References

1 comment:

  1. hi,

    Thanks for the useful snippet. I am a newbie to python. I just wanted to know once the ini file is loaded into the Dictionary object using your method, how do I iterate or loop through all the items in each section?

    Thanks a ton,
    MM

    ReplyDelete