[Python] Set defaults from JSON schema during validation

Discussão em 'Python' iniciado por Stack, Fevereiro 6, 2025.

  1. Stack

    Stack Membro Participativo

    I try to make a validator that would set defaults from a JSON schema during validation.

    I found this question: Trying to make JSON Schema validator in Python to set default values and adjusted it a bit. Since I use "jsonschema==3.2.0", I came up with such a code:

    def _with_default_setter_extension(validator_class):
    """Extend validator class with defaults setter.

    With this extension, the validator class will set all defaults from a
    schema being validated to a validated instance.
    """

    def _set_defaults(validator, properties, instance, schema):
    if not validator.is_type(instance, "object"):
    return

    valid = True
    for prop, subschema in properties.items():
    if prop in instance:
    for error in validator.descend(
    instance[prop],
    subschema,
    path=prop,
    schema_path=prop,
    ):
    valid = False
    yield error

    # set defaults only when validation is successful
    if valid:
    # set root default when instance is empty
    if not instance and "default" in schema:
    instance.update(schema["default"])
    return

    for prop, subschema in properties.items():
    if "default" in subschema and not isinstance(instance, list):
    instance.setdefault(prop, subschema["default"])

    return jsonschema.validators.extend(
    validator_class, {"properties": _set_defaults}
    )


    It works good except one case which is important for me. I wrote such a test to prove it does not work for my case:

    def test_defaults_from_oneOf_only_defaults_from_valid_schema_are_set():
    """When oneOf is used, I expect only defaults from the valid subschema to be set."""
    schema = {
    "oneOf": [
    {
    "properties": {
    "p": {"enum": ["one"]},
    "params": {"properties": {"q": {"default": 1}}},
    }
    },
    {
    "properties": {
    "p": {"enum": ["two"]},
    "params": {"properties": {"w": {"default": 2}}},
    }
    },
    ],
    }
    assert _VALIDATOR.validate({"p": "two", "params": {}}, schema) == {
    "p": "two",
    "params": {"w": 2},
    }


    The test fails with this assertion error:

    AssertionError: assert {'p': 'two', 'params': {'q': 1, 'w': 2}} == {'p': 'two', 'params': {'w': 2}}
    +{'p': 'two', 'params': {'q': 1, 'w': 2}}
    -{'p': 'two', 'params': {'w': 2}}
    Full diff:
    - {'p': 'two', 'params': {'w': 2}}
    + {'p': 'two', 'params': {'q': 1, 'w': 2}}
    ?


    So we can see, that despite the first subschema is invalid, the default value ("q") from its "params" is set. With some debugging, I discovered that when you override only the "properties" validator, it lacks context. So when the first subschema "params" gets validated, I have no context telling me that "p" param validation failed and we are still in the same subschema.

    Please, give me any insight into what I could try.

    Continue reading...

Compartilhe esta Página