Source code for clldutils.inifile

"""
This module provides an enhanced `INI format <https://en.wikipedia.org/wiki/INI_file>`_ reader and
writer based on the standard library's
`configparser <https://docs.python.org/3/library/configparser.html>`_ .
"""
import io
import re
import pathlib
import configparser


[docs]class INI(configparser.ConfigParser): """ An enhanced `ConfigParser` with better support for list-valued options and multiline text. """ @staticmethod def format_list(items): return ''.join('\n' + item for item in items) @classmethod def from_file(cls, fname, encoding='utf-8', **kw) -> 'INI': obj = cls(**kw) obj.read(str(fname), encoding=encoding) return obj def write_string(self, **kw) -> str: res = io.StringIO() res.write('# -*- coding: utf-8 -*-\n') super(INI, self).write(res, **kw) return res.getvalue()
[docs] def set(self, section, option, value=None): """ Enhances `ConfigParser.set` by - ignoring `None` values - creating missing sections - accepting `list` instances as value """ if value is None: return if not self.has_section(section): self.add_section(section) if isinstance(value, (list, tuple)): value = self.format_list(value) elif not isinstance(value, str): value = '%s' % value super(INI, self).set(section, option, value)
def getlist(self, section, option) -> list: return self.get(section, option, fallback='').strip().splitlines()
[docs] def gettext(self, section, option, whitespace_preserving_prefix='.'): """ While configparser supports multiline values, it does this at the expense of stripping leading whitespace for each line in such a value. Sometimes we want to preserve such whitespace, e.g. to be able to put markdown with nested lists into INI files. We support this be introducing a special prefix, which is prepended to lines starting with whitespace in :meth:`INI.settext` and stripped in :meth:`INI.gettext` . """ lines = [] for line in self.get(section, option, fallback='').splitlines(): if re.match(re.escape(whitespace_preserving_prefix) + r'\s+', line): line = line[len(whitespace_preserving_prefix):] lines.append(line) return '\n'.join(lines)
def settext(self, section, option, value, whitespace_preserving_prefix='.'): lines = [] for line in value.splitlines(): if re.match(r'\s+', line): line = whitespace_preserving_prefix + line lines.append(line) self.set(section, option, '\n'.join(lines))
[docs] def write(self, fname, **kw): """ Write an INI file. """ pathlib.Path(fname).write_text(self.write_string(**kw), encoding='utf-8')