0

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

Simon Fromme
  • 3,104
  • 18
  • 30
  • The point of ConfigParser *is* that it is a (relatively) standard format. Your format doesn't really fit into their scheme. – Peter Wood Mar 03 '17 at 12:44
  • What variable would you like to write into? If you instead have `variable=line1` and continue the following lines it will work fine. – Peter Wood Mar 03 '17 at 12:45
  • Maybe you could collapse all those "lines" as a single variable like `section2=line1,line2,line3`. It is also suggested [here](http://stackoverflow.com/questions/335695/lists-in-configparser). Of course it depends on your specific needs. – farsil Mar 03 '17 at 12:49
  • @PeterWood: That would certainly be a possibility but I would like to keep the format of the config file as it is (changing it would make other changes in other places necessary). I'd imagine having something like `raw_text = config.get('section2')`. – Simon Fromme Mar 03 '17 at 12:51

2 Answers2

1

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')]
>>> 
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
0

As far as I know,ConfigParser can not do this:

The ConfigParser class implements a basic configuration file parser language which provides a structure similar to what you would find on Microsoft Windows INI files.

It seems that your conf file is not a basic configuration file,so maybe two ways you can parse this conf file.

  • Read the conf file and modify it.
  • Generate a valid configuration file.
McGrady
  • 10,869
  • 13
  • 47
  • 69