mikew
mikew

Reputation: 922

Can't figure out why json-schema validation not working with recursive defs

I've simplified this to make it easier to convey, but I have a yaml I parse using PyYaml and then I want to validate it against a json-schema. I'm struggling to figure out why validation is failing against my schema when I go more than one level deep. I'm using validate from jsonschema package

Sample YAML:

TOP_LEVEL_KEY:
    first_level:
        can_be_any_value:
            some_setting: value
            second_level:
                any_value:
                    some_setting: value2

SOME_OTHER_TOP_LEVEL:
  ....

first_level and second_level are predefined to some Enum list. There can be indeterminate number of levels.

Schema:

yaml_schema = {
    '$defs': {
        'ConfigLevel': {
            'type': 'object',
            'propertyNames': {
                'enum': [
                    'first_level',
                    'second_level',
                ]
            },
            "additionalProperties": {
                'type': 'object', # the 'can_by_any_value' objects
                "additionalProperties": {
                    'type': 'object',
                    'properties': {
                        'some_setting': {
                            'type': 'string'
                        },
                    },
                    "additionalProperties": {
                        '$ref': '#/$defs/ConfigLevel'
                    }
                }
            }
        }
    },
    'type': 'object',
    'additionalProperties': {
        '$ref': '#/$defs/ConfigLevel'
    }
}

Sample as written will fail with:

jsonschema.exceptions.ValidationError: 'can_by_any_value' is not one of ['first_level', 'second_level']

But this YAML will validate

TOP_LEVEL_KEY:
    first_level:
        can_be_any_value:
            some_setting: value
    second_level:
        any_value:
            some_setting: value2

So the issue is when the recursive definition in the additionalProperties with the #/$defs/ConfigLevel but I've simplified it as far as I can go and am stuck.

Sample PyTest:

import pytest
import yaml
from jsonschema import validate

@pytest.fixture(scope="module")
def yaml_fixture() -> str:
    return """
TOP_LEVEL:
    first_level:
        can_be_any_value:
            some_setting: value
            second_level:
                can_by_any_value:
                    some_setting: value2
"""

def test_validate_yaml(yaml_fixture):
    validate(yaml.safe_load(yaml_fixture), yaml_schema)

Upvotes: -1

Views: 33

Answers (0)

Related Questions