Factor out dependencies to jsonschema.
authorBenjamin Braatz <bb@bbraatz.eu>
Fri, 3 Sep 2021 13:01:38 +0000 (15:01 +0200)
committerBenjamin Braatz <bb@bbraatz.eu>
Fri, 3 Sep 2021 13:01:38 +0000 (15:01 +0200)
controlpi/messagebus.py

index 42647e0bffe752e3f7ca955e233b50096b9eee57..3e216db458d11aa54f77ea016a8b75555d5f8626 100644 (file)
@@ -100,6 +100,37 @@ MessageCallback = Callable[['Message'], Coroutine[Any, Any, None]]
 
 # Global cache of JSON schema validators:
 _validators: Dict[str, jsonschema.Draft7Validator] = {}
+# Draft7Validator is hardcoded, because _LATEST_VERSION is non-public in
+# jsonschema and we also perhaps do not want to upgrade automatically.
+
+
+def check_schema(schema: JSONSchema) -> bool:
+    """Check if the given JSON schema is valid."""
+    try:
+        jsonschema.Draft7Validator.check_schema(schema)
+    except jsonschema.exceptions.SchemaError:
+        return False
+    return True
+
+
+def register_schema(schema: JSONSchema) -> None:
+    """Register the given JSON schema in the global cache."""
+    global _validators
+    schema_string = json.dumps(schema)
+    if schema_string not in _validators:
+        _validators[schema_string] = jsonschema.Draft7Validator(schema)
+
+
+def validate(schema_string: str, value: MessageValue) -> bool:
+    """Validate the given MessageValue against the given JSON schema string."""
+    global _validators
+    if schema_string not in _validators:
+        schema = json.loads(schema_string)
+        _validators[schema_string] = jsonschema.Draft7Validator(schema)
+    validator = _validators[schema_string]
+    for error in validator.iter_errors(value):
+        return False
+    return True
 
 
 class Message(Dict[str, MessageValue]):
@@ -428,21 +459,13 @@ class MessageTemplate(Dict[str, JSONSchema]):
         TypeError: 'schema' is not a valid value in MessageTemplate
         (not a valid JSON schema).
         """
-        global _validators
         if not isinstance(key, str):
             raise TypeError(f"'{key}' is not a valid key in MessageTemplate"
                             " (not a string).")
-        schema_string = json.dumps(value)
-        if schema_string not in _validators:
-            try:
-                jsonschema.Draft7Validator.check_schema(value)
-                # Draft7Validator is hardcoded, because _LATEST_VERSION is
-                # non-public in jsonschema and we also perhaps do not want
-                # to upgrade automatically.
-            except jsonschema.exceptions.SchemaError:
-                raise TypeError(f"'{value}' is not a valid value in"
-                                " MessageTemplate (not a valid JSON schema).")
-            _validators[schema_string] = jsonschema.Draft7Validator(value)
+        if not check_schema(value):
+            raise TypeError(f"'{value}' is not a valid value in"
+                            " MessageTemplate (not a valid JSON schema).")
+        register_schema(value)
         super().__setitem__(key, value)
 
     def update(self, *args, **kwargs) -> None:
@@ -615,8 +638,7 @@ class MessageTemplate(Dict[str, JSONSchema]):
                 return False
             else:
                 schema_string = json.dumps(self[key])
-                validator = _validators[schema_string]
-                for error in validator.iter_errors(message[key]):
+                if not validate(schema_string, message[key]):
                     return False
         return True
 
@@ -892,21 +914,12 @@ class MessageTemplateRegistry:
         {'k1': 'v2', 'k2': 'v1'}: False
         {'k1': 'v2', 'k2': 'v2'}: True
         """
-        global _validators
         if client in self._clients:
             return True
         for key in self._children:
             if key in message:
                 for schema_string in self._children[key]:
-                    if schema_string not in _validators:
-                        schema = json.loads(schema_string)
-                        _validators[schema_string] = \
-                            jsonschema.Draft7Validator(schema)
-                    validator = _validators[schema_string]
-                    validated = True
-                    for error in validator.iter_errors(message[key]):
-                        validated = False
-                    if validated:
+                    if validate(schema_string, message[key]):
                         child = self._children[key][schema_string]
                         if child.check(client, message):
                             return True
@@ -926,7 +939,6 @@ class MessageTemplateRegistry:
         {'k1': 'v2', 'k2': 'v1'}: []
         {'k1': 'v2', 'k2': 'v2'}: ['Client 2']
         """
-        global _validators
         result = []
         for client in self._clients:
             if client not in result:
@@ -934,15 +946,7 @@ class MessageTemplateRegistry:
         for key in self._children:
             if key in message:
                 for schema_string in self._children[key]:
-                    if schema_string not in _validators:
-                        schema = json.loads(schema_string)
-                        _validators[schema_string] = \
-                            jsonschema.Draft7Validator(schema)
-                    validator = _validators[schema_string]
-                    validated = True
-                    for error in validator.iter_errors(message[key]):
-                        validated = False
-                    if validated:
+                    if validate(schema_string, message[key]):
                         child = self._children[key][schema_string]
                         for client in child.get(message):
                             if client not in result: