diff options
author | Harald Nezbeda <hn@nezhar.com> | 2021-06-28 14:43:38 +0200 |
---|---|---|
committer | Harald Nezbeda <hn@nezhar.com> | 2021-07-20 17:08:48 +0200 |
commit | bede403b64d5044396af891a40e9670d0d3bb549 (patch) | |
tree | 81a84036482d8155f786f700f6c1758717140d7d | |
parent | c380b09ea9aeb9eb3a5c8ac92f0245843b113aa7 (diff) | |
download | jsonschema-bede403b64d5044396af891a40e9670d0d3bb549.tar.gz |
Julian/jsonschema#782: Resolve meta schema vocabularies from local cache
-rw-r--r-- | jsonschema/_utils.py | 16 | ||||
-rw-r--r-- | jsonschema/schemas/draft2020-12/applicator.json | 48 | ||||
-rw-r--r-- | jsonschema/schemas/draft2020-12/content.json | 17 | ||||
-rw-r--r-- | jsonschema/schemas/draft2020-12/core.json | 51 | ||||
-rw-r--r-- | jsonschema/schemas/draft2020-12/format-annotation.json | 14 | ||||
-rw-r--r-- | jsonschema/schemas/draft2020-12/meta-data.json | 37 | ||||
-rw-r--r-- | jsonschema/schemas/draft2020-12/unevaluated.json | 15 | ||||
-rw-r--r-- | jsonschema/schemas/draft2020-12/validation.json | 98 | ||||
-rw-r--r-- | jsonschema/validators.py | 24 | ||||
-rw-r--r-- | setup.cfg | 2 |
10 files changed, 317 insertions, 5 deletions
diff --git a/jsonschema/_utils.py b/jsonschema/_utils.py index fa928e6..e963e39 100644 --- a/jsonschema/_utils.py +++ b/jsonschema/_utils.py @@ -1,9 +1,12 @@ from collections.abc import Mapping, MutableMapping, Sequence +from pathlib import Path from urllib.parse import urlsplit import itertools import json +import os import pkgutil import re +import sys class URIDict(MutableMapping): @@ -55,6 +58,19 @@ def load_schema(name): return json.loads(data.decode("utf-8")) +def load_vocabulary(name): + """ + Load all schema files from ./schemas/``name`` and return them as a list. + """ + vocabulary = [] + base_path = os.path.dirname(sys.modules["jsonschema"].__file__) + pathlist = Path(os.path.join(base_path, 'schemas', name)).glob('*.json') + for path in pathlist: + with open(path) as data: + vocabulary.append(json.load(data)) + return vocabulary + + def format_as_index(indices): """ Construct a single string containing indexing operations for the indices. diff --git a/jsonschema/schemas/draft2020-12/applicator.json b/jsonschema/schemas/draft2020-12/applicator.json new file mode 100644 index 0000000..ca69923 --- /dev/null +++ b/jsonschema/schemas/draft2020-12/applicator.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/applicator", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/applicator": true + }, + "$dynamicAnchor": "meta", + + "title": "Applicator vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "prefixItems": { "$ref": "#/$defs/schemaArray" }, + "items": { "$dynamicRef": "#meta" }, + "contains": { "$dynamicRef": "#meta" }, + "additionalProperties": { "$dynamicRef": "#meta" }, + "properties": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependentSchemas": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "default": {} + }, + "propertyNames": { "$dynamicRef": "#meta" }, + "if": { "$dynamicRef": "#meta" }, + "then": { "$dynamicRef": "#meta" }, + "else": { "$dynamicRef": "#meta" }, + "allOf": { "$ref": "#/$defs/schemaArray" }, + "anyOf": { "$ref": "#/$defs/schemaArray" }, + "oneOf": { "$ref": "#/$defs/schemaArray" }, + "not": { "$dynamicRef": "#meta" } + }, + "$defs": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$dynamicRef": "#meta" } + } + } +} diff --git a/jsonschema/schemas/draft2020-12/content.json b/jsonschema/schemas/draft2020-12/content.json new file mode 100644 index 0000000..2f6e056 --- /dev/null +++ b/jsonschema/schemas/draft2020-12/content.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/content", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/content": true + }, + "$dynamicAnchor": "meta", + + "title": "Content vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "contentEncoding": { "type": "string" }, + "contentMediaType": { "type": "string" }, + "contentSchema": { "$dynamicRef": "#meta" } + } +} diff --git a/jsonschema/schemas/draft2020-12/core.json b/jsonschema/schemas/draft2020-12/core.json new file mode 100644 index 0000000..dfc092d --- /dev/null +++ b/jsonschema/schemas/draft2020-12/core.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/core", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": true + }, + "$dynamicAnchor": "meta", + + "title": "Core vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "$id": { + "$ref": "#/$defs/uriReferenceString", + "$comment": "Non-empty fragments not allowed.", + "pattern": "^[^#]*#?$" + }, + "$schema": { "$ref": "#/$defs/uriString" }, + "$ref": { "$ref": "#/$defs/uriReferenceString" }, + "$anchor": { "$ref": "#/$defs/anchorString" }, + "$dynamicRef": { "$ref": "#/$defs/uriReferenceString" }, + "$dynamicAnchor": { "$ref": "#/$defs/anchorString" }, + "$vocabulary": { + "type": "object", + "propertyNames": { "$ref": "#/$defs/uriString" }, + "additionalProperties": { + "type": "boolean" + } + }, + "$comment": { + "type": "string" + }, + "$defs": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" } + } + }, + "$defs": { + "anchorString": { + "type": "string", + "pattern": "^[A-Za-z_][-A-Za-z0-9._]*$" + }, + "uriString": { + "type": "string", + "format": "uri" + }, + "uriReferenceString": { + "type": "string", + "format": "uri-reference" + } + } +} diff --git a/jsonschema/schemas/draft2020-12/format-annotation.json b/jsonschema/schemas/draft2020-12/format-annotation.json new file mode 100644 index 0000000..51ef7ea --- /dev/null +++ b/jsonschema/schemas/draft2020-12/format-annotation.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/format-annotation", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/format-annotation": true + }, + "$dynamicAnchor": "meta", + + "title": "Format vocabulary meta-schema for annotation results", + "type": ["object", "boolean"], + "properties": { + "format": { "type": "string" } + } +} diff --git a/jsonschema/schemas/draft2020-12/meta-data.json b/jsonschema/schemas/draft2020-12/meta-data.json new file mode 100644 index 0000000..05cbc22 --- /dev/null +++ b/jsonschema/schemas/draft2020-12/meta-data.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/meta-data", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/meta-data": true + }, + "$dynamicAnchor": "meta", + + "title": "Meta-data vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "deprecated": { + "type": "boolean", + "default": false + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + } + } +} diff --git a/jsonschema/schemas/draft2020-12/unevaluated.json b/jsonschema/schemas/draft2020-12/unevaluated.json new file mode 100644 index 0000000..5f62a3f --- /dev/null +++ b/jsonschema/schemas/draft2020-12/unevaluated.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/unevaluated", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/unevaluated": true + }, + "$dynamicAnchor": "meta", + + "title": "Unevaluated applicator vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "unevaluatedItems": { "$dynamicRef": "#meta" }, + "unevaluatedProperties": { "$dynamicRef": "#meta" } + } +} diff --git a/jsonschema/schemas/draft2020-12/validation.json b/jsonschema/schemas/draft2020-12/validation.json new file mode 100644 index 0000000..606b87b --- /dev/null +++ b/jsonschema/schemas/draft2020-12/validation.json @@ -0,0 +1,98 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/validation", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/validation": true + }, + "$dynamicAnchor": "meta", + + "title": "Validation vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "type": { + "anyOf": [ + { "$ref": "#/$defs/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/$defs/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "const": true, + "enum": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, + "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, + "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, + "minContains": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 1 + }, + "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, + "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/$defs/stringArray" }, + "dependentRequired": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/stringArray" + } + } + }, + "$defs": { + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 0 + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + } +} diff --git a/jsonschema/validators.py b/jsonschema/validators.py index 328f6bc..3da5091 100644 --- a/jsonschema/validators.py +++ b/jsonschema/validators.py @@ -26,6 +26,7 @@ ErrorTree validators = {} meta_schemas = _utils.URIDict() +vocabulary_schemas = _utils.URIDict() def validates(version): @@ -53,6 +54,12 @@ def validates(version): meta_schema_id = cls.ID_OF(cls.META_SCHEMA) if meta_schema_id: meta_schemas[meta_schema_id] = cls + + for vocabulary in cls.VOCABULARY_SCHEMAS: + vocabulary_id = cls.ID_OF(vocabulary) + if vocabulary_id: + vocabulary_schemas[vocabulary_id] = vocabulary + return cls return _validates @@ -63,8 +70,18 @@ def _id_of(schema): return schema.get(u"$id", u"") +def _store_schema_list(): + return [ + (id, validator.META_SCHEMA) + for id, validator in meta_schemas.items() + ] + [ + (id, schema) for id, schema in vocabulary_schemas.items() + ] + + def create( meta_schema, + vocabulary_schemas=(), validators=(), version=None, type_checker=_types.draft7_type_checker, @@ -120,6 +137,7 @@ def create( VALIDATORS = dict(validators) META_SCHEMA = dict(meta_schema) + VOCABULARY_SCHEMAS = list(vocabulary_schemas) TYPE_CHECKER = type_checker ID_OF = staticmethod(id_of) @@ -434,6 +452,7 @@ Draft7Validator = create( Draft202012Validator = create( meta_schema=_utils.load_schema("draft2020-12"), + vocabulary_schemas=_utils.load_vocabulary("draft2020-12"), validators={ u"$ref": _validators.ref, u"$defs": _validators.defs, @@ -545,10 +564,7 @@ class RefResolver(object): self.handlers = dict(handlers) self._scopes_stack = [base_uri] - self.store = _utils.URIDict( - (id, validator.META_SCHEMA) - for id, validator in meta_schemas.items() - ) + self.store = _utils.URIDict(_store_schema_list()) self.store.update(store) self.store[base_uri] = referrer @@ -55,7 +55,7 @@ console_scripts = jsonschema = jsonschema.cli:main [options.package_data] -jsonschema = schemas/*.json +jsonschema = schemas/*.json, schemas/draft2020-12/*.json [bdist_wheel] universal = 1 |