Global cache of validators.
authorBenjamin Braatz <benjamin.braatz@graph-it.com>
Wed, 1 Sep 2021 10:22:46 +0000 (12:22 +0200)
committerBenjamin Braatz <benjamin.braatz@graph-it.com>
Wed, 1 Sep 2021 10:22:46 +0000 (12:22 +0200)
controlpi/messagebus.py

index ed9b6b21e7d80bc3ac82d252fbab0b34f4e0aa5c..30ec4b8a7e34bf1f6170e123d135a0b829a77b84 100644 (file)
@@ -98,6 +98,10 @@ JSONSchema = Union[bool, Dict[str, MessageValue]]
 MessageCallback = Callable[['Message'], Coroutine[Any, Any, None]]
 
 
+# Global cache of JSON schema validators:
+_validators: Dict[str, jsonschema.Draft7Validator] = {}
+
+
 class Message(Dict[str, MessageValue]):
     """Define arbitrary message.
 
@@ -346,7 +350,6 @@ class MessageTemplate(Dict[str, JSONSchema]):
         >>> print(t)
         {'key': {'const': 'value'}}
         """
-        self._validators: Dict[str, jsonschema.Draft7Validator] = {}
         if init is not None:
             self.update(init)
 
@@ -425,18 +428,21 @@ 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).")
-        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).")
-        self._validators[key] = jsonschema.Draft7Validator(value)
+        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)
         super().__setitem__(key, value)
 
     def update(self, *args, **kwargs) -> None:
@@ -608,7 +614,8 @@ class MessageTemplate(Dict[str, JSONSchema]):
             if key not in message:
                 return False
             else:
-                validator = self._validators[key]
+                schema_string = json.dumps(self[key])
+                validator = _validators[schema_string]
                 for error in validator.iter_errors(message[key]):
                     return False
         return True
@@ -724,7 +731,6 @@ class MessageTemplateRegistry:
 
         >>> r = MessageTemplateRegistry()
         """
-        self._validators: Dict[str, jsonschema.Draft7Validator] = {}
         self._clients: List[str] = []
         self._children: Dict[str, Dict[str, MessageTemplateRegistry]] = {}
 
@@ -880,16 +886,17 @@ 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 self._validators:
+                    if schema_string not in _validators:
                         schema = json.loads(schema_string)
-                        self._validators[schema_string] = \
+                        _validators[schema_string] = \
                             jsonschema.Draft7Validator(schema)
-                    validator = self._validators[schema_string]
+                    validator = _validators[schema_string]
                     validated = True
                     for error in validator.iter_errors(message[key]):
                         validated = False
@@ -913,6 +920,7 @@ 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:
@@ -920,11 +928,11 @@ class MessageTemplateRegistry:
         for key in self._children:
             if key in message:
                 for schema_string in self._children[key]:
-                    if schema_string not in self._validators:
+                    if schema_string not in _validators:
                         schema = json.loads(schema_string)
-                        self._validators[schema_string] = \
+                        _validators[schema_string] = \
                             jsonschema.Draft7Validator(schema)
-                    validator = self._validators[schema_string]
+                    validator = _validators[schema_string]
                     validated = True
                     for error in validator.iter_errors(message[key]):
                         validated = False