changeset 134:2f2e819e8d17

Check the return type of the JSON and YAML loading functions: they must be a dict alike
author Franz Glasner <hg@dom66.de>
date Thu, 05 Apr 2018 09:12:29 +0200
parents 05cb18c8697a
children b7b0cea8ec6e
files configmix/json.py configmix/yaml.py doc/introduction.rst tests/test.py
diffstat 4 files changed, 34 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/configmix/json.py	Wed Apr 04 23:51:07 2018 +0200
+++ b/configmix/json.py	Thu Apr 05 09:12:29 2018 +0200
@@ -53,4 +53,7 @@
         if _with_object_pairs_hook:
             kwds["object_pairs_hook"] = DictImpl
         decoder = json.decoder.JSONDecoder(**kwds)
-        return decoder.decode(jsfp.read())
+        data = decoder.decode(jsfp.read())
+        if not isinstance(data, DictImpl):
+            raise TypeError("JSON root must be an object")
+        return data
--- a/configmix/yaml.py	Wed Apr 04 23:51:07 2018 +0200
+++ b/configmix/yaml.py	Thu Apr 05 09:12:29 2018 +0200
@@ -151,16 +151,34 @@
 
 
 def load(stream, Loader=ConfigLoader):
-    return yaml.load(stream, Loader)
+    data = yaml.load(stream, Loader)
+    if OrderedDict:
+        if not isinstance(data, OrderedDict):
+            raise TypeError("YAML root object must be a mapping")
+    return data
 
 
 def load_all(stream, Loader=ConfigLoader):
-    return yaml.load_all(stream, Loader)
+    data_all = yaml.load_all(stream, Loader)
+    if OrderedDict:
+        for data in data_all:
+            if not isinstance(data, OrderedDict):
+                raise TypeError("YAML root object must be a mapping")
+    return data_all
 
 
 def safe_load(stream):
-    return yaml.load(stream, Loader=ConfigSafeLoader)
+    data = yaml.load(stream, Loader=ConfigSafeLoader)
+    if OrderedDict:
+        if not isinstance(data, OrderedDict):
+            raise TypeError("YAML root object must be a mapping")
+    return data
 
 
 def safe_load_all(stream):
-    return yaml.load_all(stream, Loader=ConfigSafeLoader)
+    data_all = yaml.load_all(stream, Loader=ConfigSafeLoader)
+    if OrderedDict:
+        for data in data_all:
+            if not isinstance(data, OrderedDict):
+                raise TypeError("YAML root object must be a mapping")
+    return data_all
--- a/doc/introduction.rst	Wed Apr 04 23:51:07 2018 +0200
+++ b/doc/introduction.rst	Thu Apr 05 09:12:29 2018 +0200
@@ -22,8 +22,9 @@
 
 .. note:: All strings are returned as Unicode text strings.
 
-.. note:: The root object must be a *mapping* and therefore decode into
-          a Python :class:`dict` alike.
+.. note:: The root object must be a *mapping* and therefore decode
+          into a Python :class:`dict` alike. This is checked by the
+          implementation.
 
 An example is:
 
@@ -40,8 +41,9 @@
 
 .. note:: All strings are returned as Unicode text strings.
 
-.. note:: The root object must be an *object* and therefore decode into
-          a Python :class:`dict` alike.
+.. note:: The root object must be an *object* and therefore decode
+          into a Python :class:`dict` alike. This is checked by the
+          implementation.
 
 .. todo:: Handle JSON comments by special attributes which will
           filtered out on further processing. Javascript comments are
--- a/tests/test.py	Wed Apr 04 23:51:07 2018 +0200
+++ b/tests/test.py	Thu Apr 05 09:12:29 2018 +0200
@@ -66,6 +66,8 @@
         with io.open(os.path.join(TESTDATADIR, "conf1.yml"), "rt",
                      encoding="utf-8") as f:
             cfg = configmix.yaml.safe_load(f)
+            if configmix.yaml.OrderedDict:
+                self.assertTrue(isinstance(cfg, configmix.yaml.OrderedDict))
             self.__check_types(cfg)
 
     def test04_json_types(self):