From e07dbb9fc6cffec501047ddc8f41e3e99beb8a3b Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 25 Dec 2022 10:38:30 +0000 Subject: [PATCH 1/5] Disable uri-reference format check. Consistently use same validator across codebase --- altair/utils/display.py | 5 ++--- altair/utils/schemapi.py | 42 ++++++++++++++++++++++++++++++++------ tools/schemapi/schemapi.py | 42 ++++++++++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/altair/utils/display.py b/altair/utils/display.py index 92d7c7835..bcf8232b3 100644 --- a/altair/utils/display.py +++ b/altair/utils/display.py @@ -4,10 +4,9 @@ from typing import Callable, Dict import uuid -from jsonschema import validate - from .plugin_registry import PluginRegistry from .mimebundle import spec_to_mimebundle +from .schemapi import validate_jsonschema # ============================================================================== @@ -126,7 +125,7 @@ def _validate(self): # type: () -> None """Validate the spec against the schema.""" schema_dict = json.loads(pkgutil.get_data(*self.schema_path).decode("utf-8")) - validate(self.spec, schema_dict) + validate_jsonschema(self.spec, schema_dict) def _repr_mimebundle_(self, include=None, exclude=None): """Return a MIME bundle for display in Jupyter frontends.""" diff --git a/altair/utils/schemapi.py b/altair/utils/schemapi.py index 5e6256252..94a55a37d 100644 --- a/altair/utils/schemapi.py +++ b/altair/utils/schemapi.py @@ -4,12 +4,14 @@ import contextlib import inspect import json +import warnings from typing import Any import jsonschema import numpy as np import pandas as pd +JSONSCHEMA_VALIDATOR = jsonschema.Draft7Validator # If DEBUG_MODE is True, then schema objects are converted to dict and # validated at creation time. This slows things down, particularly for @@ -40,6 +42,36 @@ def debug_mode(arg): DEBUG_MODE = original +def validate_jsonschema(*args, **kwargs): + # We always want to use the same jsonschema validator across the whole codebase + validator_cls = JSONSCHEMA_VALIDATOR + if "cls" in kwargs: + warnings.warn("The cls argument will be overwritten by the default validator") + kwargs["cls"] = validator_cls + + removed_format_checkers = [] + try: + # The "uri-reference" checker fails for some of the Vega-Lite + # schemas as URIs in "$ref" are not encoded, + # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but + # it is not a valid URI reference due to the characters such as '<'. + # This is fine and we can disable this format check below- + for format_name in ["uri-reference"]: + try: + checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) + removed_format_checkers.append((format_name, checker)) + except KeyError: + continue + output = jsonschema.validate(*args, **kwargs) + finally: + # Restore the original set of checkers as the jsonschema package + # might also be used by other packages + for format_name, checker in removed_format_checkers: + validator_cls.FORMAT_CHECKER.checkers[format_name] = checker + return output + + def _subclasses(cls): """Breadth-first sequence of all classes which inherit from cls.""" seen = set() @@ -155,7 +187,7 @@ class SchemaBase(object): _schema = None _rootschema = None _class_is_valid_at_instantiation = True - _validator = jsonschema.Draft7Validator + _validator = JSONSCHEMA_VALIDATOR def __init__(self, *args, **kwds): # Two valid options for initialization, which should be handled by @@ -445,9 +477,7 @@ def validate(cls, instance, schema=None): if schema is None: schema = cls._schema resolver = jsonschema.RefResolver.from_schema(cls._rootschema or cls._schema) - return jsonschema.validate( - instance, schema, cls=cls._validator, resolver=resolver - ) + return validate_jsonschema(instance, schema, resolver=resolver) @classmethod def resolve_references(cls, schema=None): @@ -466,7 +496,7 @@ def validate_property(cls, name, value, schema=None): value = _todict(value, validate=False, context={}) props = cls.resolve_references(schema or cls._schema).get("properties", {}) resolver = jsonschema.RefResolver.from_schema(cls._rootschema or cls._schema) - return jsonschema.validate(value, props.get(name, {}), resolver=resolver) + return validate_jsonschema(value, props.get(name, {}), resolver=resolver) def __dir__(self): return list(self._kwds.keys()) @@ -560,7 +590,7 @@ def from_dict( for possible_schema in schemas: resolver = jsonschema.RefResolver.from_schema(rootschema) try: - jsonschema.validate(dct, possible_schema, resolver=resolver) + validate_jsonschema(dct, possible_schema, resolver=resolver) except jsonschema.ValidationError: continue else: diff --git a/tools/schemapi/schemapi.py b/tools/schemapi/schemapi.py index 7895733c5..e1f617a5c 100644 --- a/tools/schemapi/schemapi.py +++ b/tools/schemapi/schemapi.py @@ -2,12 +2,14 @@ import contextlib import inspect import json +import warnings from typing import Any import jsonschema import numpy as np import pandas as pd +JSONSCHEMA_VALIDATOR = jsonschema.Draft7Validator # If DEBUG_MODE is True, then schema objects are converted to dict and # validated at creation time. This slows things down, particularly for @@ -38,6 +40,36 @@ def debug_mode(arg): DEBUG_MODE = original +def validate_jsonschema(*args, **kwargs): + # We always want to use the same jsonschema validator across the whole codebase + validator_cls = JSONSCHEMA_VALIDATOR + if "cls" in kwargs: + warnings.warn("The cls argument will be overwritten by the default validator") + kwargs["cls"] = validator_cls + + removed_format_checkers = [] + try: + # The "uri-reference" checker fails for some of the Vega-Lite + # schemas as URIs in "$ref" are not encoded, + # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but + # it is not a valid URI reference due to the characters such as '<'. + # This is fine and we can disable this format check below- + for format_name in ["uri-reference"]: + try: + checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) + removed_format_checkers.append((format_name, checker)) + except KeyError: + continue + output = jsonschema.validate(*args, **kwargs) + finally: + # Restore the original set of checkers as the jsonschema package + # might also be used by other packages + for format_name, checker in removed_format_checkers: + validator_cls.FORMAT_CHECKER.checkers[format_name] = checker + return output + + def _subclasses(cls): """Breadth-first sequence of all classes which inherit from cls.""" seen = set() @@ -153,7 +185,7 @@ class SchemaBase(object): _schema = None _rootschema = None _class_is_valid_at_instantiation = True - _validator = jsonschema.Draft7Validator + _validator = JSONSCHEMA_VALIDATOR def __init__(self, *args, **kwds): # Two valid options for initialization, which should be handled by @@ -443,9 +475,7 @@ def validate(cls, instance, schema=None): if schema is None: schema = cls._schema resolver = jsonschema.RefResolver.from_schema(cls._rootschema or cls._schema) - return jsonschema.validate( - instance, schema, cls=cls._validator, resolver=resolver - ) + return validate_jsonschema(instance, schema, resolver=resolver) @classmethod def resolve_references(cls, schema=None): @@ -464,7 +494,7 @@ def validate_property(cls, name, value, schema=None): value = _todict(value, validate=False, context={}) props = cls.resolve_references(schema or cls._schema).get("properties", {}) resolver = jsonschema.RefResolver.from_schema(cls._rootschema or cls._schema) - return jsonschema.validate(value, props.get(name, {}), resolver=resolver) + return validate_jsonschema(value, props.get(name, {}), resolver=resolver) def __dir__(self): return list(self._kwds.keys()) @@ -558,7 +588,7 @@ def from_dict( for possible_schema in schemas: resolver = jsonschema.RefResolver.from_schema(rootschema) try: - jsonschema.validate(dct, possible_schema, resolver=resolver) + validate_jsonschema(dct, possible_schema, resolver=resolver) except jsonschema.ValidationError: continue else: From 95cf20636e181c4da66fdfb0b44dc1187aa7fe44 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 25 Dec 2022 10:43:07 +0000 Subject: [PATCH 2/5] Remove validation in SchemaInfo as not used anywhere and it referenced the wrong jsonschema draft --- tools/schemapi/jsonschema-draft04.json | 149 ------------------------- tools/schemapi/utils.py | 14 +-- 2 files changed, 1 insertion(+), 162 deletions(-) delete mode 100644 tools/schemapi/jsonschema-draft04.json diff --git a/tools/schemapi/jsonschema-draft04.json b/tools/schemapi/jsonschema-draft04.json deleted file mode 100644 index bcbb84743..000000000 --- a/tools/schemapi/jsonschema-draft04.json +++ /dev/null @@ -1,149 +0,0 @@ -{ - "id": "http://json-schema.org/draft-04/schema#", - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Core schema meta-schema", - "definitions": { - "schemaArray": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#" } - }, - "positiveInteger": { - "type": "integer", - "minimum": 0 - }, - "positiveIntegerDefault0": { - "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] - }, - "simpleTypes": { - "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] - }, - "stringArray": { - "type": "array", - "items": { "type": "string" }, - "minItems": 1, - "uniqueItems": true - } - }, - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "$schema": { - "type": "string" - }, - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "default": {}, - "multipleOf": { - "type": "number", - "minimum": 0, - "exclusiveMinimum": true - }, - "maximum": { - "type": "number" - }, - "exclusiveMaximum": { - "type": "boolean", - "default": false - }, - "minimum": { - "type": "number" - }, - "exclusiveMinimum": { - "type": "boolean", - "default": false - }, - "maxLength": { "$ref": "#/definitions/positiveInteger" }, - "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, - "pattern": { - "type": "string", - "format": "regex" - }, - "additionalItems": { - "anyOf": [ - { "type": "boolean" }, - { "$ref": "#" } - ], - "default": {} - }, - "items": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/schemaArray" } - ], - "default": {} - }, - "maxItems": { "$ref": "#/definitions/positiveInteger" }, - "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, - "uniqueItems": { - "type": "boolean", - "default": false - }, - "maxProperties": { "$ref": "#/definitions/positiveInteger" }, - "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, - "required": { "$ref": "#/definitions/stringArray" }, - "additionalProperties": { - "anyOf": [ - { "type": "boolean" }, - { "$ref": "#" } - ], - "default": {} - }, - "definitions": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "properties": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "patternProperties": { - "type": "object", - "additionalProperties": { "$ref": "#" }, - "default": {} - }, - "dependencies": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/stringArray" } - ] - } - }, - "enum": { - "type": "array", - "minItems": 1, - "uniqueItems": true - }, - "type": { - "anyOf": [ - { "$ref": "#/definitions/simpleTypes" }, - { - "type": "array", - "items": { "$ref": "#/definitions/simpleTypes" }, - "minItems": 1, - "uniqueItems": true - } - ] - }, - "format": { "type": "string" }, - "allOf": { "$ref": "#/definitions/schemaArray" }, - "anyOf": { "$ref": "#/definitions/schemaArray" }, - "oneOf": { "$ref": "#/definitions/schemaArray" }, - "not": { "$ref": "#" } - }, - "dependencies": { - "exclusiveMaximum": [ "maximum" ], - "exclusiveMinimum": [ "minimum" ] - }, - "default": {} -} diff --git a/tools/schemapi/utils.py b/tools/schemapi/utils.py index d0b149f3f..5a73c96cd 100644 --- a/tools/schemapi/utils.py +++ b/tools/schemapi/utils.py @@ -1,8 +1,6 @@ """Utilities for working with schemas""" -import json import keyword -import pkgutil import re import textwrap import urllib @@ -13,12 +11,6 @@ EXCLUDE_KEYS = ("definitions", "title", "description", "$schema", "id") -def load_metaschema(): - schema = pkgutil.get_data("schemapi", "jsonschema-draft04.json") - schema = schema.decode() - return json.loads(schema) - - def resolve_references(schema, root=None): """Resolve References within a JSON schema""" resolver = jsonschema.RefResolver.from_schema(root or schema) @@ -144,7 +136,7 @@ def values(self): class SchemaInfo(object): """A wrapper for inspecting a JSON schema""" - def __init__(self, schema, rootschema=None, validate=False): + def __init__(self, schema, rootschema=None): if hasattr(schema, "_schema"): if hasattr(schema, "_rootschema"): schema, rootschema = schema._schema, schema._rootschema @@ -152,10 +144,6 @@ def __init__(self, schema, rootschema=None, validate=False): schema, rootschema = schema._schema, schema._schema elif not rootschema: rootschema = schema - if validate: - metaschema = load_metaschema() - jsonschema.validate(schema, metaschema) - jsonschema.validate(rootschema, metaschema) self.raw_schema = schema self.rootschema = rootschema self.schema = resolve_references(schema, rootschema) From 44d84764a1c157a57b26d51fd7a5c1a0f98f9c3c Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 25 Dec 2022 12:19:12 +0000 Subject: [PATCH 3/5] Add compatibility for older jsonschema versions --- altair/utils/schemapi.py | 27 +++++++++++++++------------ tools/schemapi/schemapi.py | 27 +++++++++++++++------------ 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/altair/utils/schemapi.py b/altair/utils/schemapi.py index 94a55a37d..7d6a9d6cd 100644 --- a/altair/utils/schemapi.py +++ b/altair/utils/schemapi.py @@ -51,18 +51,21 @@ def validate_jsonschema(*args, **kwargs): removed_format_checkers = [] try: - # The "uri-reference" checker fails for some of the Vega-Lite - # schemas as URIs in "$ref" are not encoded, - # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but - # it is not a valid URI reference due to the characters such as '<'. - # This is fine and we can disable this format check below- - for format_name in ["uri-reference"]: - try: - checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) - removed_format_checkers.append((format_name, checker)) - except KeyError: - continue + # In older versions of jsonschema this attribute did not yet exist + # and we do not need to disable any format checkers + if hasattr(validator_cls, "FORMAT_CHECKER"): + # The "uri-reference" checker fails for some of the Vega-Lite + # schemas as URIs in "$ref" are not encoded, + # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but + # it is not a valid URI reference due to the characters such as '<'. + # This is fine and we can disable this format check below- + for format_name in ["uri-reference"]: + try: + checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) + removed_format_checkers.append((format_name, checker)) + except KeyError: + continue output = jsonschema.validate(*args, **kwargs) finally: # Restore the original set of checkers as the jsonschema package diff --git a/tools/schemapi/schemapi.py b/tools/schemapi/schemapi.py index e1f617a5c..0bfacce62 100644 --- a/tools/schemapi/schemapi.py +++ b/tools/schemapi/schemapi.py @@ -49,18 +49,21 @@ def validate_jsonschema(*args, **kwargs): removed_format_checkers = [] try: - # The "uri-reference" checker fails for some of the Vega-Lite - # schemas as URIs in "$ref" are not encoded, - # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but - # it is not a valid URI reference due to the characters such as '<'. - # This is fine and we can disable this format check below- - for format_name in ["uri-reference"]: - try: - checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) - removed_format_checkers.append((format_name, checker)) - except KeyError: - continue + # In older versions of jsonschema this attribute did not yet exist + # and we do not need to disable any format checkers + if hasattr(validator_cls, "FORMAT_CHECKER"): + # The "uri-reference" checker fails for some of the Vega-Lite + # schemas as URIs in "$ref" are not encoded, + # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but + # it is not a valid URI reference due to the characters such as '<'. + # This is fine and we can disable this format check below- + for format_name in ["uri-reference"]: + try: + checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) + removed_format_checkers.append((format_name, checker)) + except KeyError: + continue output = jsonschema.validate(*args, **kwargs) finally: # Restore the original set of checkers as the jsonschema package From d8b1a2ac8249a4c7aab9b1796f3f00ece99f0e41 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 25 Dec 2022 12:22:17 +0000 Subject: [PATCH 4/5] Improve comments --- altair/utils/schemapi.py | 4 +++- tools/schemapi/schemapi.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/altair/utils/schemapi.py b/altair/utils/schemapi.py index 7d6a9d6cd..b485c5dcf 100644 --- a/altair/utils/schemapi.py +++ b/altair/utils/schemapi.py @@ -59,12 +59,14 @@ def validate_jsonschema(*args, **kwargs): # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but # it is not a valid URI reference due to the characters such as '<'. - # This is fine and we can disable this format check below- + # This is fine and we can disable this format check below. for format_name in ["uri-reference"]: try: checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) removed_format_checkers.append((format_name, checker)) except KeyError: + # Format checks are only set by jsonschema if it can import + # the relevant dependencies continue output = jsonschema.validate(*args, **kwargs) finally: diff --git a/tools/schemapi/schemapi.py b/tools/schemapi/schemapi.py index 0bfacce62..a118daecd 100644 --- a/tools/schemapi/schemapi.py +++ b/tools/schemapi/schemapi.py @@ -57,12 +57,14 @@ def validate_jsonschema(*args, **kwargs): # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but # it is not a valid URI reference due to the characters such as '<'. - # This is fine and we can disable this format check below- + # This is fine and we can disable this format check below. for format_name in ["uri-reference"]: try: checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) removed_format_checkers.append((format_name, checker)) except KeyError: + # Format checks are only set by jsonschema if it can import + # the relevant dependencies continue output = jsonschema.validate(*args, **kwargs) finally: From 9c3b9649b6eba611c33110d03c71128c63b0ea87 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Mon, 2 Jan 2023 17:04:26 +0000 Subject: [PATCH 5/5] Simplify validate_jsonschema --- altair/utils/schemapi.py | 51 +++++++++++++------------------------- tools/schemapi/schemapi.py | 51 +++++++++++++------------------------- 2 files changed, 34 insertions(+), 68 deletions(-) diff --git a/altair/utils/schemapi.py b/altair/utils/schemapi.py index b485c5dcf..b1a1b9754 100644 --- a/altair/utils/schemapi.py +++ b/altair/utils/schemapi.py @@ -4,10 +4,10 @@ import contextlib import inspect import json -import warnings from typing import Any import jsonschema +import jsonschema.exceptions import numpy as np import pandas as pd @@ -42,39 +42,22 @@ def debug_mode(arg): DEBUG_MODE = original -def validate_jsonschema(*args, **kwargs): - # We always want to use the same jsonschema validator across the whole codebase - validator_cls = JSONSCHEMA_VALIDATOR - if "cls" in kwargs: - warnings.warn("The cls argument will be overwritten by the default validator") - kwargs["cls"] = validator_cls - - removed_format_checkers = [] - try: - # In older versions of jsonschema this attribute did not yet exist - # and we do not need to disable any format checkers - if hasattr(validator_cls, "FORMAT_CHECKER"): - # The "uri-reference" checker fails for some of the Vega-Lite - # schemas as URIs in "$ref" are not encoded, - # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but - # it is not a valid URI reference due to the characters such as '<'. - # This is fine and we can disable this format check below. - for format_name in ["uri-reference"]: - try: - checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) - removed_format_checkers.append((format_name, checker)) - except KeyError: - # Format checks are only set by jsonschema if it can import - # the relevant dependencies - continue - output = jsonschema.validate(*args, **kwargs) - finally: - # Restore the original set of checkers as the jsonschema package - # might also be used by other packages - for format_name, checker in removed_format_checkers: - validator_cls.FORMAT_CHECKER.checkers[format_name] = checker - return output +def validate_jsonschema(spec, schema, resolver=None): + # We don't use jsonschema.validate as this would validate the schema itself. + # Instead, we pass the schema directly to the validator class. This is done for + # two reasons: The schema comes from Vega-Lite and is not based on the user + # input, therefore there is no need to validate it in the first place. Furthermore, + # the "uri-reference" format checker fails for some of the references as URIs in + # "$ref" are not encoded, + # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but + # it is not a valid URI reference due to the characters such as '<'. + validator = JSONSCHEMA_VALIDATOR( + schema, format_checker=JSONSCHEMA_VALIDATOR.FORMAT_CHECKER, resolver=resolver + ) + error = jsonschema.exceptions.best_match(validator.iter_errors(spec)) + if error is not None: + raise error def _subclasses(cls): diff --git a/tools/schemapi/schemapi.py b/tools/schemapi/schemapi.py index a118daecd..c43ffa26f 100644 --- a/tools/schemapi/schemapi.py +++ b/tools/schemapi/schemapi.py @@ -2,10 +2,10 @@ import contextlib import inspect import json -import warnings from typing import Any import jsonschema +import jsonschema.exceptions import numpy as np import pandas as pd @@ -40,39 +40,22 @@ def debug_mode(arg): DEBUG_MODE = original -def validate_jsonschema(*args, **kwargs): - # We always want to use the same jsonschema validator across the whole codebase - validator_cls = JSONSCHEMA_VALIDATOR - if "cls" in kwargs: - warnings.warn("The cls argument will be overwritten by the default validator") - kwargs["cls"] = validator_cls - - removed_format_checkers = [] - try: - # In older versions of jsonschema this attribute did not yet exist - # and we do not need to disable any format checkers - if hasattr(validator_cls, "FORMAT_CHECKER"): - # The "uri-reference" checker fails for some of the Vega-Lite - # schemas as URIs in "$ref" are not encoded, - # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but - # it is not a valid URI reference due to the characters such as '<'. - # This is fine and we can disable this format check below. - for format_name in ["uri-reference"]: - try: - checker = validator_cls.FORMAT_CHECKER.checkers.pop(format_name) - removed_format_checkers.append((format_name, checker)) - except KeyError: - # Format checks are only set by jsonschema if it can import - # the relevant dependencies - continue - output = jsonschema.validate(*args, **kwargs) - finally: - # Restore the original set of checkers as the jsonschema package - # might also be used by other packages - for format_name, checker in removed_format_checkers: - validator_cls.FORMAT_CHECKER.checkers[format_name] = checker - return output +def validate_jsonschema(spec, schema, resolver=None): + # We don't use jsonschema.validate as this would validate the schema itself. + # Instead, we pass the schema directly to the validator class. This is done for + # two reasons: The schema comes from Vega-Lite and is not based on the user + # input, therefore there is no need to validate it in the first place. Furthermore, + # the "uri-reference" format checker fails for some of the references as URIs in + # "$ref" are not encoded, + # e.g. '#/definitions/ValueDefWithCondition' would be a valid $ref in a Vega-Lite schema but + # it is not a valid URI reference due to the characters such as '<'. + validator = JSONSCHEMA_VALIDATOR( + schema, format_checker=JSONSCHEMA_VALIDATOR.FORMAT_CHECKER, resolver=resolver + ) + error = jsonschema.exceptions.best_match(validator.iter_errors(spec)) + if error is not None: + raise error def _subclasses(cls):