validator.py
147 lines
| 4.4 KiB
| text/x-python
|
PythonLexer
MinRK
|
r18243 | # Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||||
Thomas Kluyver
|
r13348 | from __future__ import print_function | ||
Thomas Kluyver
|
r12547 | import json | ||
Jessica B. Hamrick
|
r16330 | import os | ||
MinRK
|
r18251 | import warnings | ||
Matthias BUSSONNIER
|
r8519 | |||
Paul Ivanov
|
r16998 | try: | ||
MinRK
|
r18243 | from jsonschema import ValidationError | ||
from jsonschema import Draft4Validator as Validator | ||||
Paul Ivanov
|
r16998 | except ImportError as e: | ||
verbose_msg = """ | ||||
Paul Ivanov
|
r16999 | |||
MinRK
|
r18243 | IPython notebook format depends on the jsonschema package: | ||
Paul Ivanov
|
r16998 | |||
MinRK
|
r18243 | https://pypi.python.org/pypi/jsonschema | ||
Paul Ivanov
|
r17000 | |||
Please install it first. | ||||
""" | ||||
MinRK
|
r17029 | raise ImportError(str(e) + verbose_msg) | ||
Paul Ivanov
|
r17000 | |||
MinRK
|
r18243 | from IPython.utils.importstring import import_item | ||
Matthias BUSSONNIER
|
r8519 | |||
Jessica B. Hamrick
|
r16330 | |||
MinRK
|
r18243 | validators = {} | ||
Jessica B. Hamrick
|
r16330 | |||
MinRK
|
r18251 | def _relax_additional_properties(obj): | ||
"""relax any `additionalProperties`""" | ||||
if isinstance(obj, dict): | ||||
for key, value in obj.items(): | ||||
if key == 'additionalProperties': | ||||
print(obj) | ||||
value = True | ||||
else: | ||||
value = _relax_additional_properties(value) | ||||
obj[key] = value | ||||
elif isinstance(obj, list): | ||||
for i, value in enumerate(obj): | ||||
obj[i] = _relax_additional_properties(value) | ||||
return obj | ||||
def get_validator(version=None, version_minor=None): | ||||
MinRK
|
r18243 | """Load the JSON schema into a Validator""" | ||
if version is None: | ||||
MinRK
|
r18603 | from .. import current_nbformat | ||
version = current_nbformat | ||||
Jessica B. Hamrick
|
r16330 | |||
MinRK
|
r18251 | v = import_item("IPython.nbformat.v%s" % version) | ||
current_minor = v.nbformat_minor | ||||
if version_minor is None: | ||||
version_minor = current_minor | ||||
version_tuple = (version, version_minor) | ||||
if version_tuple not in validators: | ||||
MinRK
|
r18250 | try: | ||
v.nbformat_schema | ||||
except AttributeError: | ||||
# no validator | ||||
return None | ||||
MinRK
|
r18243 | schema_path = os.path.join(os.path.dirname(v.__file__), v.nbformat_schema) | ||
with open(schema_path) as f: | ||||
schema_json = json.load(f) | ||||
MinRK
|
r18251 | if current_minor < version_minor: | ||
# notebook from the future, relax all `additionalProperties: False` requirements | ||||
schema_json = _relax_additional_properties(schema_json) | ||||
validators[version_tuple] = Validator(schema_json) | ||||
return validators[version_tuple] | ||||
def isvalid(nbjson, ref=None, version=None, version_minor=None): | ||||
Jessica B. Hamrick
|
r16347 | """Checks whether the given notebook JSON conforms to the current | ||
notebook format schema. Returns True if the JSON is valid, and | ||||
False otherwise. | ||||
Jessica B. Hamrick
|
r16407 | To see the individual errors that were encountered, please use the | ||
`validate` function instead. | ||||
Jessica B. Hamrick
|
r16347 | """ | ||
MinRK
|
r18243 | try: | ||
MinRK
|
r18251 | validate(nbjson, ref, version, version_minor) | ||
MinRK
|
r18243 | except ValidationError: | ||
return False | ||||
else: | ||||
return True | ||||
Jessica B. Hamrick
|
r16341 | |||
MinRK
|
r18251 | def better_validation_error(error, version, version_minor): | ||
MinRK
|
r18245 | """Get better ValidationError on oneOf failures | ||
oneOf errors aren't informative. | ||||
if it's a cell type or output_type error, | ||||
try validating directly based on the type for a better error message | ||||
""" | ||||
key = error.schema_path[-1] | ||||
if key.endswith('Of'): | ||||
ref = None | ||||
if isinstance(error.instance, dict): | ||||
if 'cell_type' in error.instance: | ||||
ref = error.instance['cell_type'] + "_cell" | ||||
elif 'output_type' in error.instance: | ||||
ref = error.instance['output_type'] | ||||
if ref: | ||||
try: | ||||
validate(error.instance, | ||||
ref, | ||||
MinRK
|
r18251 | version=version, | ||
version_minor=version_minor, | ||||
MinRK
|
r18245 | ) | ||
except ValidationError as e: | ||||
MinRK
|
r18251 | return better_validation_error(e, version, version_minor) | ||
MinRK
|
r18245 | except: | ||
# if it fails for some reason, | ||||
# let the original error through | ||||
pass | ||||
return error | ||||
MinRK
|
r18251 | def validate(nbjson, ref=None, version=None, version_minor=None): | ||
Jessica B. Hamrick
|
r16347 | """Checks whether the given notebook JSON conforms to the current | ||
MinRK
|
r18243 | notebook format schema. | ||
Jessica B. Hamrick
|
r16347 | |||
MinRK
|
r18243 | Raises ValidationError if not valid. | ||
Jessica B. Hamrick
|
r16347 | """ | ||
MinRK
|
r18243 | if version is None: | ||
MinRK
|
r18251 | from .reader import get_version | ||
(version, version_minor) = get_version(nbjson) | ||||
Jessica B. Hamrick
|
r16347 | |||
MinRK
|
r18251 | validator = get_validator(version, version_minor) | ||
Matthias BUSSONNIER
|
r8519 | |||
MinRK
|
r18250 | if validator is None: | ||
# no validator | ||||
MinRK
|
r18251 | warnings.warn("No schema for validating v%s notebooks" % version, UserWarning) | ||
MinRK
|
r18250 | return | ||
MinRK
|
r18245 | try: | ||
if ref: | ||||
return validator.validate(nbjson, {'$ref' : '#/definitions/%s' % ref}) | ||||
else: | ||||
return validator.validate(nbjson) | ||||
except ValidationError as e: | ||||
MinRK
|
r18251 | raise better_validation_error(e, version, version_minor) | ||
Jessica B. Hamrick
|
r16335 | |||