changeset 38:5a2fba996773

Implement a "forbidden" schema field for dicts
author Franz Glasner <f.glasner@feldmann-mg.com>
date Wed, 19 Jul 2023 13:30:55 +0200
parents ef586378f79a
children 78f5ef0ee087
files data_schema/__init__.py docs/schema.txt tests/test_schema.py
diffstat 3 files changed, 23 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/data_schema/__init__.py	Wed Jul 19 13:26:06 2023 +0200
+++ b/data_schema/__init__.py	Wed Jul 19 13:30:55 2023 +0200
@@ -118,6 +118,7 @@
     E10056 = NC_("schema-msg", "failing `any-of' item")
     E10057 = NC_("schema-msg", "`all-of' failed")
     E10058 = NC_("schema-msg", "failing `all-of' item")
+    E10059 = NC_("schema-msg", "forbidden key detected")
 
 
 @enum.unique
@@ -738,6 +739,14 @@
     if not required_keys <= seen_keys:
         hs = [str(i) for i in required_keys - seen_keys]
         yield ValidationProblem(code=ERRORS.E10005, hint=sorted(hs), context=context)
+    # check whether no forbidden keys are seen
+    try:
+        forbidden_keys = set(schema.get("forbidden", set()))
+    except (TypeError, ValueError):
+        raise SchemaError("`forbidden` must be an iterable")
+    if forbidden_keys & seen_keys:
+        hs = [str(i) for i in forbidden_keys & seen_keys]
+        yield ValidationProblem(code=ERRORS.E10059, hint=sorted(hs), context=context)
 
 
 def validate_list(obj, schema, context):
--- a/docs/schema.txt	Wed Jul 19 13:26:06 2023 +0200
+++ b/docs/schema.txt	Wed Jul 19 13:30:55 2023 +0200
@@ -52,7 +52,7 @@
 
   A callable with an `uri` argument that returns a file-alike and a
   context manager to be feed into the schema loader.
-                 
+
 - ``schema_loader``
 
   Default: configmix.yaml.load (if available) or ``None``
@@ -118,6 +118,10 @@
 
   Liste von Strings mit Key-Namen, die vorkommen müssen
 
+- ``forbidden``
+
+  Liste von Strings mit Key-Namen, die **nicht** vorkommen dürfen
+
 - ``max-length``
 - ``min-length``
 
--- a/tests/test_schema.py	Wed Jul 19 13:26:06 2023 +0200
+++ b/tests/test_schema.py	Wed Jul 19 13:30:55 2023 +0200
@@ -1607,6 +1607,15 @@
              "key-names": {"$type": "int"}}))
         self.assertEqual(0, len(pr))
 
+    def test_d11_forbidden_keys(self):
+        pr = list(data_schema.validate(
+            {"key": 1234, "key-2": 5678},
+            {"$type": "dict",
+             "additional-keys": True,
+             "forbidden": ["key"]}))
+        self.assertEqual(1, len(pr))
+        self.assertEqual(ERRORS.E10059, pr[0].code)
+
     def test_error_message(self):
         self.assertEqual("dict expected",
                          data_schema.problem_message(ERRORS.E10000))