Search code examples
pythonpython-2.7configparser

Using ConfigParser to read non-standard config files


I am having a config file of the form

# foo.conf

[section1]
foo=bar
buzz=123

[section2]
line1
line2
line3

that I want to parse using the Python ConfigParser library. Note that section2 does not contain key/value pairs but some raw text instead. I would like to have a possibility to read all (raw) content of section2 to a variable.

Does ConfigParser allow me to read this file or can one of its classes be subclassed in an easy manner to do so?

Using the standard

import ConfigParser

config = ConfigParser.ConfigParser()
config.read('foo.conf')

yields ConfigParser.ParsingError: File contains parsing errors: foo.conf


Solution

  • You could try to use an io adapter to transform the input file in a format suitable for ConfigParser. A way for that would be to tranform plain line that are neither empty line, nor comment line, nor section lines not key=value line in linei=original_line, where i is increased at each line and starts at 1 in each section.

    A possible code could be:

    class ConfParsAdapter(io.RawIOBase):
        @staticmethod
        def _confParsAdapter(fd):
            num=1
            rxsec = re.compile('\[.*\]( *#.*)?$')
            rxkv = re.compile('.+?=.*')
            rxvoid = re.compile('(#.*)?$')
            for line in fd:
                if rxsec.match(line.strip()):
                    num=1
                elif rxkv.match(line) or rxvoid.match(line.strip()):
                    pass
                else:
                    line = 'line{}={}'.format(num, line)
                    num += 1
                yield(line)
    
        def __init__(self, fd):
            self.fd = self._confParsAdapter(fd)
        def readline(self, hint = -1):
            try:
                return next(self.fd)
            except StopIteration:
                return ""
    

    That way, you could use with your current file without changing anything in it:

    >>> parser = ConfigParser.RawConfigParser()
    >>> parser.readfp(ConfParsAdapter(open('foo.conf'))
    >>> parser.sections()
    ['section1', 'section2']
    >>> parser.items('section2')
    [('line1', 'line1'), ('line2', 'line2'), ('line3', 'line3')]
    >>>