Mercurial > hgrepos > Python > libs > ConfigMix
changeset 122:21d92ff8cf31
Begin the handling of JSON-style configuration files
| author | Franz Glasner <hg@dom66.de> |
|---|---|
| date | Wed, 04 Apr 2018 09:45:29 +0200 |
| parents | 0d378dcc018b |
| children | 4218c66b9281 |
| files | CHANGES.txt README.txt configmix/__init__.py configmix/json.py doc/apidoc.rst doc/introduction.rst tests/data/conf1.json tests/test.py |
| diffstat | 8 files changed, 81 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/CHANGES.txt Fri Mar 30 08:48:25 2018 +0200 +++ b/CHANGES.txt Wed Apr 04 09:45:29 2018 +0200 @@ -46,6 +46,11 @@ Build a tree of configuration settings from INI files + .. change:: + :tags: feature + + Allow JSON formatted files as configuration files also (suffix ".json"). + .. changelog:: :version: 0.5
--- a/README.txt Fri Mar 30 08:48:25 2018 +0200 +++ b/README.txt Wed Apr 04 09:45:29 2018 +0200 @@ -18,6 +18,7 @@ It reads configuration files in the following styles: - YAML files +- JSON files - INI files - executable Python scripts
--- a/configmix/__init__.py Fri Mar 30 08:48:25 2018 +0200 +++ b/configmix/__init__.py Wed Apr 04 09:45:29 2018 +0200 @@ -64,6 +64,9 @@ from . import yaml with open(filename, "rb") as yf: return yaml.safe_load(yf) + elif fnl.endswith(".json"): + from . import json + return json.load(filename) elif fnl.endswith(".py"): from . import py return py.load(filename)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configmix/json.py Wed Apr 04 09:45:29 2018 +0200 @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +#- +# :Copyright: (c) 2018, Franz Glasner. All rights reserved. +# :License: 3-clause BSD. See LICENSE.txt for details. +#- +"""Read JSON-style configuration files. + +""" + +from __future__ import division, absolute_import, print_function + +import io +import json.decoder + + +__all__ = ["load"] + + +def load(filename, encoding="utf-8"): + """Load a single JSON file with name `filename` and encoding `encoding`. + + .. todo:: Allow comments in JSON files + + .. todo:: Allow all Python string literals + + .. todo:: Use OrderedDict as default mapping implementation (Python 2.7+) + + """ + with io.open(filename, "rt", encoding=encoding) as jsfp: + decoder = json.decoder.JSONDecoder( + encoding=encoding, + parse_int=lambda n: int(n, 0), + strict=False) + return decoder.decode(jsfp.read())
--- a/doc/apidoc.rst Fri Mar 30 08:48:25 2018 +0200 +++ b/doc/apidoc.rst Wed Apr 04 09:45:29 2018 +0200 @@ -60,3 +60,11 @@ .. automodule:: configmix.yaml :members: :ignore-module-all: + + +Module :mod:`configmix.json` +---------------------------- + +.. automodule:: configmix.json + :members: + :ignore-module-all:
--- a/doc/introduction.rst Fri Mar 30 08:48:25 2018 +0200 +++ b/doc/introduction.rst Wed Apr 04 09:45:29 2018 +0200 @@ -8,6 +8,7 @@ The configurations can be read from different types of files: - :ref:`YAML files <yaml-files>` +- :ref:`JSON files <json-files>` - :ref:`INI files <ini-files>` - :ref:`executable Python scripts <executable-python-scripts>` @@ -28,6 +29,14 @@ :language: yaml +.. _json-files: + +JSON files +---------- + +.. todo:: Document basic JSON usage + + .. _ini-files: INI Files @@ -138,6 +147,9 @@ ``.yml`` or ``.yaml`` for YAML configuration files + ``.json`` + for JSON configuration files + ``.ini`` for INI configuration files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/data/conf1.json Wed Apr 04 09:45:29 2018 +0200 @@ -0,0 +1,8 @@ +{"key1": "the value", + "key2": 2, + "key3": 5.7, + "key4": true, + "key5": false, + "key6": 255, + "key7": "Umlaute: ÄÖÜäöüß" +}
--- a/tests/test.py Fri Mar 30 08:48:25 2018 +0200 +++ b/tests/test.py Wed Apr 04 09:45:29 2018 +0200 @@ -14,6 +14,7 @@ import configmix import configmix.ini import configmix.yaml +import configmix.json import configmix.py from configmix.compat import u @@ -67,29 +68,33 @@ cfg = configmix.yaml.safe_load(f) self.__check_types(cfg) - def test04_py_export_all(self): + def test04_json_types(self): + cfg = configmix.json.load(os.path.join(TESTDATADIR, "conf1.json")) + self.__check_types(cfg) + + def test05_py_export_all(self): # When __all__ is given only it's keys are exported cfg = configmix.py.load(os.path.join(TESTDATADIR, "conf2.py")) self.assertEqual(u("the next value"), cfg.get("key1")) self.assertTrue(isinstance(cfg.get("key1"), type(u('')))) self.assertTrue(cfg.get("key2") is None) - def test05_py_hide_private(self): + def test06_py_hide_private(self): # When no __all__ is given all symbols with leading "_" are hidden cfg = configmix.py.load(os.path.join(TESTDATADIR, "conf3.py")) self.assertEqual(u("the next value "), cfg.get("key1")) self.assertTrue(isinstance(cfg.get("key1"), type(u('')))) self.assertTrue(cfg.get("_key2") is None) - def test06_ini_tree(self): + def test07_ini_tree(self): cfg = configmix.ini.load(os.path.join(TESTDATADIR, "conf10.ini")) self.__check_tree(cfg) - def test07_py_tree(self): + def test08_py_tree(self): cfg = configmix.py.load(os.path.join(TESTDATADIR, "conf10.py")) self.__check_tree(cfg) - def test08_yaml_tree(self): + def test09_yaml_tree(self): with io.open(os.path.join(TESTDATADIR, "conf10.yml"), "rt", encoding="utf-8") as f: cfg = configmix.yaml.safe_load(f)
