Recursive schema extension
The following script implements the recursive schema extension example, described in the JSON Schema 2020-12 core specification.
import pprint
from jschon import create_catalog, JSON, JSONSchema
# create a catalog with support for JSON Schema version 2020-12
create_catalog('2020-12')
# define an extensible tree schema
tree_schema = JSONSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/tree",
"$dynamicAnchor": "node",
"type": "object",
"properties": {
"data": True,
"children": {
"type": "array",
"items": {
"$dynamicRef": "#node"
}
}
}
})
# define a strict-tree schema, which guards against misspelled properties
strict_tree_schema = JSONSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/strict-tree",
"$dynamicAnchor": "node",
"$ref": "tree",
"unevaluatedProperties": False
})
# declare a JSON instance with a misspelled field
tree_json = JSON({
"children": [{"daat": 1}]
})
# evaluate the JSON instance with the tree schema
tree_result = tree_schema.evaluate(tree_json)
# evaluate the JSON instance with the strict-tree schema
strict_tree_result = strict_tree_schema.evaluate(tree_json)
# print output for the tree case
print('Tree schema verbose output:')
pprint.pp(tree_result.output('verbose'))
# print output for the strict-tree case
print('Strict tree schema verbose output:')
pprint.pp(strict_tree_result.output('verbose'))
The script produces the output shown below. The 'verbose'
output
format reflects the complete dynamic evaluation path through a schema
and any referenced schemas.
Tree schema verbose output:
{'valid': True,
'instanceLocation': '',
'keywordLocation': '',
'absoluteKeywordLocation': 'https://example.com/tree#',
'annotations': [{'valid': True,
'instanceLocation': '',
'keywordLocation': '/type',
'absoluteKeywordLocation': 'https://example.com/tree#/type'},
{'valid': True,
'instanceLocation': '',
'keywordLocation': '/properties',
'absoluteKeywordLocation': 'https://example.com/tree#/properties',
'annotation': ['children'],
'annotations': [{'valid': True,
'instanceLocation': '/children',
'keywordLocation': '/properties/children',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children',
'annotations': [{'valid': True,
'instanceLocation': '/children',
'keywordLocation': '/properties/children/type',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/type'},
{'valid': True,
'instanceLocation': '/children',
'keywordLocation': '/properties/children/items',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/items',
'annotation': True,
'annotations': [{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/properties/children/items/$dynamicRef',
'absoluteKeywordLocation': 'https://example.com/tree',
'annotations': [{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/properties/children/items/$dynamicRef/type',
'absoluteKeywordLocation': 'https://example.com/tree#/type'},
{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/properties/children/items/$dynamicRef/properties',
'absoluteKeywordLocation': 'https://example.com/tree#/properties',
'annotation': []}]}]}]}]}]}
Strict tree schema verbose output:
{'valid': False,
'instanceLocation': '',
'keywordLocation': '',
'absoluteKeywordLocation': 'https://example.com/strict-tree#',
'errors': [{'valid': False,
'instanceLocation': '',
'keywordLocation': '/$ref',
'absoluteKeywordLocation': 'https://example.com/tree',
'errors': [{'valid': True,
'instanceLocation': '',
'keywordLocation': '/$ref/type',
'absoluteKeywordLocation': 'https://example.com/tree#/type'},
{'valid': False,
'instanceLocation': '',
'keywordLocation': '/$ref/properties',
'absoluteKeywordLocation': 'https://example.com/tree#/properties',
'error': "Properties ['children'] are invalid",
'errors': [{'valid': False,
'instanceLocation': '/children',
'keywordLocation': '/$ref/properties/children',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children',
'errors': [{'valid': True,
'instanceLocation': '/children',
'keywordLocation': '/$ref/properties/children/type',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/type'},
{'valid': False,
'instanceLocation': '/children',
'keywordLocation': '/$ref/properties/children/items',
'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/items',
'error': [0],
'errors': [{'valid': False,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef',
'absoluteKeywordLocation': 'https://example.com/strict-tree',
'errors': [{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef/$ref',
'absoluteKeywordLocation': 'https://example.com/tree',
'annotations': [{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef/$ref/type',
'absoluteKeywordLocation': 'https://example.com/tree#/type'},
{'valid': True,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef/$ref/properties',
'absoluteKeywordLocation': 'https://example.com/tree#/properties',
'annotation': []}]},
{'valid': False,
'instanceLocation': '/children/0',
'keywordLocation': '/$ref/properties/children/items/$dynamicRef/unevaluatedProperties',
'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
'error': ['daat']}]}]}]}]}]},
{'valid': False,
'instanceLocation': '',
'keywordLocation': '/unevaluatedProperties',
'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
'error': ['children']}]}