Mercurial > hgrepos > Python > libs > ConfigMix
changeset 97:1b4d95f60650
Build a tree-ish configuration from an INI style configuration file
| author | Franz Glasner <hg@dom66.de> |
|---|---|
| date | Sun, 18 Mar 2018 19:15:01 +0100 |
| parents | 778c3bb1fb41 |
| children | d6ba53ce2091 |
| files | CHANGES.txt configmix/ini.py doc/introduction.rst tests/data/conf10.ini tests/data/conf10.py tests/data/conf10.yml tests/test.py |
| diffstat | 7 files changed, 114 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/CHANGES.txt Sun Mar 18 19:13:35 2018 +0100 +++ b/CHANGES.txt Sun Mar 18 19:15:01 2018 +0100 @@ -1,4 +1,4 @@ -.. -*- coding: utf-8; mode: rst; -*- +.. -*- coding: utf-8; mode: rst; indent-tags-mode: nil; -*- .. .. Valid tags: doc, feature, bugfix, test @@ -24,9 +24,14 @@ Begin formal unittests + .. change:: + :tags: feature + + Build a tree of configuration settings from INI files + .. changelog:: :version: 0.5 - :released: 2016-04-19 + :released: 2016-04-19 .. change:: :tags: feature
--- a/configmix/ini.py Sun Mar 18 19:13:35 2018 +0100 +++ b/configmix/ini.py Sun Mar 18 19:15:01 2018 +0100 @@ -69,7 +69,7 @@ def readfp(self, fp, filename): """Read from a file-like object `fp`. - The `fp` argument must have a `readline()` method. + The `fp` argument must have a `readline()` method. """ if hasattr(self, "filename"): @@ -149,6 +149,9 @@ Flattens the given sections into the resulting dictionary. + Then build a tree out of sections which start with any of the `extract` + content value and a point ``.``. + """ conf = DictImpl() ini = INIConfigParser(filename) @@ -161,4 +164,17 @@ for option in cfg: value = ini.getx(sect, option) conf[option] = value + # try to read "<extract>.xxx" sections as tree + for treemarker in [ e + '.' for e in extract ]: + sections = list(ini.sections()) + sections.sort() + for section in sections: + cur_cfg = conf + if section.startswith(treemarker): + treestr = section[len(treemarker):] + for treepart in treestr.split('.'): + cur_cfg = cur_cfg.setdefault(treepart, DictImpl()) + for option in ini.options(section): + value = ini.getx(section, option) + cur_cfg[option] = value return conf
--- a/doc/introduction.rst Sun Mar 18 19:13:35 2018 +0100 +++ b/doc/introduction.rst Sun Mar 18 19:15:01 2018 +0100 @@ -28,6 +28,12 @@ .. note:: All strings are returned as Unicode text strings. +An example is: + +.. literalinclude:: ../tests/data/conf10.yml + :language: yaml + + .. _ini-files: INI Files @@ -63,9 +69,20 @@ .. note:: Contrary to the behaviour of the standard Python :mod:`configparser` module the INI file reader is *case-sensitive*. -.. todo:: Implement tree-ish interpretation of INI files +.. todo:: Document the build of tree-ish configuration settings out of + INI files. + +The example INI style configuration below yields an equivalent +configuration to the YAML configuration above: - Currently there is no tree. +.. literalinclude:: ../tests/data/conf10.ini + :language: ini + +As can be seen in thie example -- INI file internal value interpolation +is done as in Python's standard :mod:`configparser` module. + +This example also illustrates how INI sections are used to build a +tree-ish configuration dictionary. .. _executable-python-scripts: @@ -90,3 +107,9 @@ .. note:: The Python configuration files are evaluated with ``exec`` and not imported. + +The example configuration by Python script below yields an equivalent +configuration to the YAML configuration above: + +.. literalinclude:: ../tests/data/conf10.py + :language: python
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/data/conf10.ini Sun Mar 18 19:15:01 2018 +0100 @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +[DEFAULT] +replvalue1 = in the root namespace -- too + +[config] +key1 = in the root namespace +key2 = %(replvalue1)s + +[config.tree1] +key3 = :int:0x20 + +[config.tree1.tree2] +key4 = get this as `tree1.tree2.key4' +key5 = :bool:TRUE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/data/conf10.py Sun Mar 18 19:15:01 2018 +0100 @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +key1 = u"in the root namespace" +key2 = u"in the root namespace -- too" + +tree1 = { + 'key3': 0x20, + + 'tree2': { + 'key4': u"get this as `tree1.tree2.key4'", + 'key5': True + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/data/conf10.yml Sun Mar 18 19:15:01 2018 +0100 @@ -0,0 +1,12 @@ +# -*- coding: utf-8; mode: yaml; indent-tabs-mode: nil; -*- +%YAML 1.1 +--- + +key1: in the root namespace +key2: in the root namespace -- too + +tree1: + key3: 0x20 + tree2: + key4: get this as `tree1.tree2.key4' + key5: true
--- a/tests/test.py Sun Mar 18 19:13:35 2018 +0100 +++ b/tests/test.py Sun Mar 18 19:15:01 2018 +0100 @@ -38,6 +38,17 @@ self.assertTrue(isinstance(cfg.get("key5"), bool)) self.assertEqual(255, cfg.get("key6")) + def __check_tree(self, cfg): + self.assertEqual(u("in the root namespace"), + cfg.get("key1")) + self.assertEqual(u("in the root namespace -- too"), + cfg.get("key2")) + self.assertEqual(32, + cfg["tree1"]["key3"]) + self.assertEqual(u("get this as `tree1.tree2.key4'"), + cfg["tree1"]["tree2"]["key4"]) + self.assertTrue(cfg["tree1"]["tree2"]["key5"]) + def test01_ini_types(self): cfg = configmix.ini.load(os.path.join(TESTDATADIR, "conf1.ini")) self.__check_types(cfg) @@ -65,6 +76,19 @@ self.assertTrue(isinstance(cfg.get("key1"), type(u('')))) self.assertTrue(cfg.get("_key2") is None) + def test06_ini_tree(self): + cfg = configmix.ini.load(os.path.join(TESTDATADIR, "conf10.ini")) + self.__check_tree(cfg) + + def test07_py_tree(self): + cfg = configmix.py.load(os.path.join(TESTDATADIR, "conf10.py")) + self.__check_tree(cfg) + + def test08_yaml_tree(self): + with open(os.path.join(TESTDATADIR, "conf10.yml"), "rt") as f: + cfg = configmix.yaml.safe_load(f) + self.__check_tree(cfg) + if __name__ == "__main__": unittest.main()
