3

I have some config file like this:

[main]
key_one   =
  hello
    this
      is
        indented

But when I read it using the configparser library in python like so:

import configparser
cfg = configparser.ConfigParser()
cfg.read("path/to/file.ini")
print(cfg["main"]["key_one"])

Prints out:

hello
this
is
indented

I've tried using tabs, more than two spaces per indent, nothing seems to work. How can I get configparser to recognize indents?

Jonathan Allen Grant
  • 3,408
  • 6
  • 30
  • 53
  • Try putting quotes around it – Barmar Mar 26 '20 at 19:16
  • Quotes are included the value, with leading and trailing whitespace continuing to be removed. I don't think the file format supports formatted text. – chepner Mar 26 '20 at 19:18
  • @pitto How do I try with string literal? – Jonathan Allen Grant Mar 26 '20 at 19:21
  • 1
    @Pitto That's Python source code syntax, not config file syntax. – Barmar Mar 26 '20 at 19:29
  • 1
    If you read the documentation of the file format, it says that indentation is used to recognize multi-line values. The amount of indentation is ignored, except that it has to be indented more than the initial line of the key. – Barmar Mar 26 '20 at 19:30
  • Note, too, that the newline following the `=` is considered part of the value. – chepner Mar 26 '20 at 19:30
  • 1
    Whitespaces are stripped in the configparser source. [Link here](https://github.com/python/cpython/blob/08faf0016e1ee590c78f64ddb244767c7801866a/Lib/configparser.py#L1038) you would need to overwrite the _read() method and remove stripping. – Maurice Meyer Mar 26 '20 at 19:33
  • 2
    I would hesitate to duplicate a 100+-line private method just to remove one line, though. – chepner Mar 26 '20 at 19:42

1 Answers1

5

The parser itself will always strip leading whitespace; as far as I can tell, there is no (recommended) way to change that.

A workaround is to use a non-whitespace character to indicate the beginning of your formatted text, then strip that after reading the file. For example,

[main]
key_one   =| hello
           |   this
           |     is
           |       indented

Then in your script

import configparser
import re

cfg = configparser.ConfigParser()
cfg.read("tmp.ini")
t = cfg["main"]["key_one"]
t = re.sub("^\|", "", t, flags=re.MULTILINE)
print(t)

which produces

$ python3 tmp.py
 hello
   this
     is
       indented

The value starts immediately after the = (I moved your first line up, assuming you didn't really want the value to start with a newline character). The parser preserves any non-trailing whitespace after |, as the first non-whitespace character on each line. re.sub will remove the initial | from each line, leaving the desired indented multi-line string as the result.

chepner
  • 497,756
  • 71
  • 530
  • 681