Recursive schema extension

The following script implements the recursive schema extension example, described in the JSON Schema 2020-12 core specification.

It also demonstrates the various output formats that are available.

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(f'Tree schema result: {tree_result.valid}')
print('Tree schema flag output:')
pprint.pp(tree_result.output('flag'))
print('Tree schema basic output:')
pprint.pp(tree_result.output('basic'))
print('Tree schema detailed output:')
pprint.pp(tree_result.output('detailed'))
print('Tree schema verbose output:')
pprint.pp(tree_result.output('verbose'))

# print output for the strict-tree case
print(f'Strict tree schema result: {strict_tree_result.valid}')
print('Strict tree schema flag output:')
pprint.pp(strict_tree_result.output('flag'))
print('Strict tree schema basic output:')
pprint.pp(strict_tree_result.output('basic'))
print('Strict tree schema detailed output:')
pprint.pp(strict_tree_result.output('detailed'))
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 result: True
Tree schema flag output:
{'valid': True}
Tree schema basic output:
{'valid': True,
 'annotations': [{'instanceLocation': '',
                  'keywordLocation': '/properties',
                  'absoluteKeywordLocation': 'https://example.com/tree#/properties',
                  'annotation': ['children']},
                 {'instanceLocation': '/children',
                  'keywordLocation': '/properties/children/items',
                  'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/items',
                  'annotation': True},
                 {'instanceLocation': '/children/0',
                  'keywordLocation': '/properties/children/items/$dynamicRef/properties',
                  'absoluteKeywordLocation': 'https://example.com/tree#/properties',
                  'annotation': []}]}
Tree schema detailed output:
{'valid': True,
 'instanceLocation': '',
 'keywordLocation': '',
 'absoluteKeywordLocation': 'https://example.com/tree#',
 'annotations': [{'instanceLocation': '',
                  'keywordLocation': '/type',
                  'absoluteKeywordLocation': 'https://example.com/tree#/type'},
                 {'instanceLocation': '/children',
                  'keywordLocation': '/properties/children',
                  'absoluteKeywordLocation': 'https://example.com/tree#/properties/children',
                  'annotations': [{'instanceLocation': '/children',
                                   'keywordLocation': '/properties/children/type',
                                   'absoluteKeywordLocation': 'https://example.com/tree#/properties/children/type'},
                                  {'instanceLocation': '/children/0',
                                   'keywordLocation': '/properties/children/items/$dynamicRef',
                                   'absoluteKeywordLocation': 'https://example.com/tree',
                                   'annotations': [{'instanceLocation': '/children/0',
                                                    'keywordLocation': '/properties/children/items/$dynamicRef/type',
                                                    'absoluteKeywordLocation': 'https://example.com/tree#/type'},
                                                   {'instanceLocation': '/children/0',
                                                    'keywordLocation': '/properties/children/items/$dynamicRef/properties',
                                                    'absoluteKeywordLocation': 'https://example.com/tree#/properties',
                                                    'annotation': []}]}]}]}
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 result: False
Strict tree schema flag output:
{'valid': False}
Strict tree schema basic output:
{'valid': False,
 'errors': [{'instanceLocation': '',
             'keywordLocation': '/$ref/properties',
             'absoluteKeywordLocation': 'https://example.com/tree#/properties',
             'error': "Properties ['children'] are invalid"},
            {'instanceLocation': '/children/0',
             'keywordLocation': '/$ref/properties/children/items/$dynamicRef/unevaluatedProperties',
             'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
             'error': 'The instance is disallowed by a boolean false schema'},
            {'instanceLocation': '',
             'keywordLocation': '/unevaluatedProperties',
             'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
             'error': 'The instance is disallowed by a boolean false schema'}]}
Strict tree schema detailed output:
{'valid': False,
 'instanceLocation': '',
 'keywordLocation': '',
 'absoluteKeywordLocation': 'https://example.com/strict-tree#',
 'errors': [{'instanceLocation': '/children/0',
             'keywordLocation': '/$ref/properties/children/items/$dynamicRef/unevaluatedProperties',
             'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
             'error': 'The instance is disallowed by a boolean false schema'},
            {'instanceLocation': '',
             'keywordLocation': '/unevaluatedProperties',
             'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
             'error': 'The instance is disallowed by a boolean false schema'}]}
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',
                                                 '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': 'The '
                                                                                  'instance '
                                                                                  'is '
                                                                                  'disallowed '
                                                                                  'by '
                                                                                  'a '
                                                                                  'boolean '
                                                                                  'false '
                                                                                  'schema'}]}]}]}]}]},
            {'valid': False,
             'instanceLocation': '',
             'keywordLocation': '/unevaluatedProperties',
             'absoluteKeywordLocation': 'https://example.com/strict-tree#/unevaluatedProperties',
             'error': 'The instance is disallowed by a boolean false schema'}]}