Skip to content

Commit

Permalink
Disable uri-reference format check. Consistently use same validator a…
Browse files Browse the repository at this point in the history
…cross codebase
  • Loading branch information
binste committed Dec 25, 2022
1 parent dfb11f5 commit 88ffe9f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 15 deletions.
5 changes: 2 additions & 3 deletions altair/utils/display.py
Expand Up @@ -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


# ==============================================================================
Expand Down Expand Up @@ -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."""
Expand Down
41 changes: 35 additions & 6 deletions altair/utils/schemapi.py
Expand Up @@ -2,6 +2,7 @@
# tools/generate_schema_wrapper.py. Do not modify directly.
import collections
import contextlib
import functools
import inspect
import json
from typing import Any
Expand All @@ -10,6 +11,7 @@
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
Expand Down Expand Up @@ -40,6 +42,35 @@ def debug_mode(arg):
DEBUG_MODE = original


@functools.wraps(jsonschema.validate)
def validate_jsonschema(*args, **kwargs):
# We always want to use the same jsonschema validator across the whole codebase
validator_cls = JSONSCHEMA_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<MarkPropFieldOrDatumDef,
# (Gradient|string|null)>' 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()
Expand Down Expand Up @@ -155,7 +186,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
Expand Down Expand Up @@ -445,9 +476,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):
Expand All @@ -466,7 +495,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())
Expand Down Expand Up @@ -560,7 +589,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:
Expand Down
41 changes: 35 additions & 6 deletions tools/schemapi/schemapi.py
@@ -1,5 +1,6 @@
import collections
import contextlib
import functools
import inspect
import json
from typing import Any
Expand All @@ -8,6 +9,7 @@
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
Expand Down Expand Up @@ -38,6 +40,35 @@ def debug_mode(arg):
DEBUG_MODE = original


@functools.wraps(jsonschema.validate)
def validate_jsonschema(*args, **kwargs):
# We always want to use the same jsonschema validator across the whole codebase
validator_cls = JSONSCHEMA_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<MarkPropFieldOrDatumDef,
# (Gradient|string|null)>' 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()
Expand Down Expand Up @@ -153,7 +184,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
Expand Down Expand Up @@ -443,9 +474,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):
Expand All @@ -464,7 +493,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())
Expand Down Expand Up @@ -558,7 +587,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:
Expand Down

0 comments on commit 88ffe9f

Please sign in to comment.