diff options
Diffstat (limited to 'lib/python/qmk/json_schema.py')
| -rw-r--r-- | lib/python/qmk/json_schema.py | 45 |
1 files changed, 31 insertions, 14 deletions
diff --git a/lib/python/qmk/json_schema.py b/lib/python/qmk/json_schema.py index f3992ee71..ffc7c6bcd 100644 --- a/lib/python/qmk/json_schema.py +++ b/lib/python/qmk/json_schema.py | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | """ | 2 | """ |
| 3 | import json | 3 | import json |
| 4 | from collections.abc import Mapping | 4 | from collections.abc import Mapping |
| 5 | from functools import lru_cache | ||
| 5 | from pathlib import Path | 6 | from pathlib import Path |
| 6 | 7 | ||
| 7 | import hjson | 8 | import hjson |
| @@ -25,11 +26,13 @@ def json_load(json_file): | |||
| 25 | exit(1) | 26 | exit(1) |
| 26 | 27 | ||
| 27 | 28 | ||
| 29 | @lru_cache(maxsize=0) | ||
| 28 | def load_jsonschema(schema_name): | 30 | def load_jsonschema(schema_name): |
| 29 | """Read a jsonschema file from disk. | 31 | """Read a jsonschema file from disk. |
| 30 | |||
| 31 | FIXME(skullydazed/anyone): Refactor to make this a public function. | ||
| 32 | """ | 32 | """ |
| 33 | if Path(schema_name).exists(): | ||
| 34 | return json_load(schema_name) | ||
| 35 | |||
| 33 | schema_path = Path(f'data/schemas/{schema_name}.jsonschema') | 36 | schema_path = Path(f'data/schemas/{schema_name}.jsonschema') |
| 34 | 37 | ||
| 35 | if not schema_path.exists(): | 38 | if not schema_path.exists(): |
| @@ -38,28 +41,42 @@ def load_jsonschema(schema_name): | |||
| 38 | return json_load(schema_path) | 41 | return json_load(schema_path) |
| 39 | 42 | ||
| 40 | 43 | ||
| 41 | def keyboard_validate(data): | 44 | @lru_cache(maxsize=0) |
| 42 | """Validates data against the keyboard jsonschema. | 45 | def compile_schema_store(): |
| 46 | """Compile all our schemas into a schema store. | ||
| 43 | """ | 47 | """ |
| 44 | schema = load_jsonschema('keyboard') | 48 | schema_store = {} |
| 45 | validator = jsonschema.Draft7Validator(schema).validate | ||
| 46 | 49 | ||
| 47 | return validator(data) | 50 | for schema_file in Path('data/schemas').glob('*.jsonschema'): |
| 51 | schema_data = load_jsonschema(schema_file) | ||
| 52 | if not isinstance(schema_data, dict): | ||
| 53 | cli.log.debug('Skipping schema file %s', schema_file) | ||
| 54 | continue | ||
| 55 | schema_store[schema_data['$id']] = schema_data | ||
| 56 | |||
| 57 | return schema_store | ||
| 58 | |||
| 59 | |||
| 60 | @lru_cache(maxsize=0) | ||
| 61 | def create_validator(schema): | ||
| 62 | """Creates a validator for the given schema id. | ||
| 63 | """ | ||
| 64 | schema_store = compile_schema_store() | ||
| 65 | resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store) | ||
| 66 | |||
| 67 | return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate | ||
| 48 | 68 | ||
| 49 | 69 | ||
| 50 | def keyboard_api_validate(data): | 70 | def validate(data, schema): |
| 51 | """Validates data against the api_keyboard jsonschema. | 71 | """Validates data against a schema. |
| 52 | """ | 72 | """ |
| 53 | base = load_jsonschema('keyboard') | 73 | validator = create_validator(schema) |
| 54 | relative = load_jsonschema('api_keyboard') | ||
| 55 | resolver = jsonschema.RefResolver.from_schema(base) | ||
| 56 | validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate | ||
| 57 | 74 | ||
| 58 | return validator(data) | 75 | return validator(data) |
| 59 | 76 | ||
| 60 | 77 | ||
| 61 | def deep_update(origdict, newdict): | 78 | def deep_update(origdict, newdict): |
| 62 | """Update a dictionary in place, recursing to do a deep copy. | 79 | """Update a dictionary in place, recursing to do a depth-first deep copy. |
| 63 | """ | 80 | """ |
| 64 | for key, value in newdict.items(): | 81 | for key, value in newdict.items(): |
| 65 | if isinstance(value, Mapping): | 82 | if isinstance(value, Mapping): |
