From ab48b2f949c8d950960a9813b3754375a84b65e1 Mon Sep 17 00:00:00 2001 From: Benjamin Braatz Date: Fri, 3 Sep 2021 15:01:38 +0200 Subject: [PATCH] Factor out dependencies to jsonschema. --- controlpi/messagebus.py | 72 ++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/controlpi/messagebus.py b/controlpi/messagebus.py index 42647e0..3e216db 100644 --- a/controlpi/messagebus.py +++ b/controlpi/messagebus.py @@ -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: -- 2.34.1