validator.py
112 lines
| 3.0 KiB
| text/x-python
|
PythonLexer
Thomas Kluyver
|
r13348 | from __future__ import print_function | ||
Thomas Kluyver
|
r12547 | import json | ||
Jessica B. Hamrick
|
r16330 | import os | ||
Matthias BUSSONNIER
|
r8519 | |||
Paul Ivanov
|
r16998 | try: | ||
from jsonschema import SchemaError | ||||
from jsonschema import Draft3Validator as Validator | ||||
except ImportError as e: | ||||
verbose_msg = """ | ||||
Paul Ivanov
|
r16999 | |||
IPython depends on the jsonschema package: https://pypi.python.org/pypi/jsonschema | ||||
Paul Ivanov
|
r16998 | |||
Paul Ivanov
|
r16999 | Please install it first. | ||
Paul Ivanov
|
r16998 | """ | ||
MinRK
|
r17029 | raise ImportError(str(e) + verbose_msg) | ||
Paul Ivanov
|
r17000 | |||
try: | ||||
import jsonpointer as jsonpointer | ||||
except ImportError as e: | ||||
verbose_msg = """ | ||||
IPython depends on the jsonpointer package: https://pypi.python.org/pypi/jsonpointer | ||||
Please install it first. | ||||
""" | ||||
MinRK
|
r17029 | raise ImportError(str(e) + verbose_msg) | ||
Paul Ivanov
|
r17000 | |||
Thomas Kluyver
|
r13361 | from IPython.utils.py3compat import iteritems | ||
Matthias BUSSONNIER
|
r8519 | |||
Jessica B. Hamrick
|
r16330 | |||
from .current import nbformat, nbformat_schema | ||||
Jessica B. Hamrick
|
r16335 | schema_path = os.path.join( | ||
Jessica B. Hamrick
|
r16406 | os.path.dirname(__file__), "v%d" % nbformat, nbformat_schema) | ||
Jessica B. Hamrick
|
r16330 | |||
Jessica B. Hamrick
|
r16407 | def isvalid(nbjson): | ||
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 | |||
""" | ||||
Jessica B. Hamrick
|
r16407 | errors = validate(nbjson) | ||
Jessica B. Hamrick
|
r16429 | return errors == [] | ||
Jessica B. Hamrick
|
r16341 | |||
Jessica B. Hamrick
|
r16407 | def validate(nbjson): | ||
Jessica B. Hamrick
|
r16347 | """Checks whether the given notebook JSON conforms to the current | ||
Jessica B. Hamrick
|
r16407 | notebook format schema, and returns the list of errors. | ||
Jessica B. Hamrick
|
r16347 | |||
""" | ||||
Jessica B. Hamrick
|
r16335 | # load the schema file | ||
with open(schema_path, 'r') as fh: | ||||
schema_json = json.load(fh) | ||||
# resolve internal references | ||||
Jessica B. Hamrick
|
r16908 | schema = resolve_ref(schema_json) | ||
schema = jsonpointer.resolve_pointer(schema, '/notebook') | ||||
Jessica B. Hamrick
|
r16335 | |||
Jessica B. Hamrick
|
r16347 | # count how many errors there are | ||
Jessica B. Hamrick
|
r16911 | v = Validator(schema) | ||
Jessica B. Hamrick
|
r16429 | errors = list(v.iter_errors(nbjson)) | ||
Matthias BUSSONNIER
|
r8519 | return errors | ||
Jessica B. Hamrick
|
r16330 | |||
Jessica B. Hamrick
|
r16335 | def resolve_ref(json, schema=None): | ||
Jessica B. Hamrick
|
r16347 | """Resolve internal references within the given JSON. This essentially | ||
means that dictionaries of this form: | ||||
{"$ref": "/somepointer"} | ||||
will be replaced with the resolved reference to `/somepointer`. | ||||
This only supports local reference to the same JSON file. | ||||
Matthias BUSSONNIER
|
r8519 | |||
""" | ||||
Jessica B. Hamrick
|
r16335 | if not schema: | ||
schema = json | ||||
# if it's a list, resolve references for each item in the list | ||||
Matthias BUSSONNIER
|
r8519 | if type(json) is list: | ||
Jessica B. Hamrick
|
r16335 | resolved = [] | ||
Matthias BUSSONNIER
|
r8519 | for item in json: | ||
Jessica B. Hamrick
|
r16335 | resolved.append(resolve_ref(item, schema=schema)) | ||
# if it's a dictionary, resolve references for each item in the | ||||
# dictionary | ||||
Matthias BUSSONNIER
|
r8519 | elif type(json) is dict: | ||
Jessica B. Hamrick
|
r16335 | resolved = {} | ||
for key, ref in iteritems(json): | ||||
Jessica B. Hamrick
|
r16347 | |||
Jessica B. Hamrick
|
r16335 | # if the key is equal to $ref, then replace the entire | ||
# dictionary with the resolved value | ||||
Matthias BUSSONNIER
|
r8519 | if key == '$ref': | ||
Jessica B. Hamrick
|
r16347 | if len(json) != 1: | ||
raise SchemaError( | ||||
"objects containing a $ref should only have one item") | ||||
Jessica B. Hamrick
|
r16335 | pointer = jsonpointer.resolve_pointer(schema, ref) | ||
resolved = resolve_ref(pointer, schema=schema) | ||||
Jessica B. Hamrick
|
r16332 | else: | ||
Jessica B. Hamrick
|
r16335 | resolved[key] = resolve_ref(ref, schema=schema) | ||
# otherwise it's a normal object, so just return it | ||||
Jessica B. Hamrick
|
r16332 | else: | ||
Jessica B. Hamrick
|
r16335 | resolved = json | ||
return resolved | ||||