Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended Validations Don't Work For Referenced Schemas #1163

Closed
pype-leila opened this issue Sep 14, 2023 · 1 comment
Closed

Extended Validations Don't Work For Referenced Schemas #1163

pype-leila opened this issue Sep 14, 2023 · 1 comment
Labels
Invalid Not a bug, PEBKAC, or an unsupported setup

Comments

@pype-leila
Copy link

pype-leila commented Sep 14, 2023

I was previously using jsonschema version 3.2.0 and am in the process of upgrading to 4.17.3 to bring this application in line with what others are already using. This application makes use of an extender to add default properties to the JSON and references for subschemas -- to a local file. This works correctly on 3.2.0. However, on version 4.17.3, the referenced schema default properties are not being added.

I've traced this to a difference between versions 4.9.0 and 4.10.3, specifically this commit: 18a64d7 which replaces the evolve function.

Example:

{
    "$schema"     : "http://json-schema.org/draft-07/schema#",
    "title"       : "Main Schema",
    "description" : "Main schema with JSON validation",

    "type": "object",
    "properties": {
        "number": {
            "description": "The number. Must be a unique integer.",
            "type": "integer"
        },
        "type": {
            "description": "The type.",
            "type": "string",
            "enum": ["A", "B"]
        },
        "metadata": {
            "description": "Metadata",
            "type": "object",
            "default": {}
        },
        "extra": {
            "description": "Another value",
            "type": "object"
        }
    },
    "allOf": [
        {
            "if": { "properties": { "type": { "const": "A" } } },
            "then": { "properties": { "extra": { "$ref": "type_a.json" } } }
        },
        {
            "if": { "properties": { "type": { "const": "B" } } },
            "then": { "properties": { "extra": { "$ref": "type_b.json" } } }
        }
    ],
    "required": [
        "number",
        "type"
    ],
    "additionalProperties": false
}
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "Type A Schema",
    "description": "The format of the A type",
    "id": "type_a.json/type_a",

    "type": "object",
    "properties": {
        "propertyX": {
            "description": "Property X",
            "type": "boolean"
        },
        "propertyY": {
            "description": "Property Y",
            "type": ["integer", "null"],
            "default": null
        },
        "propertyZ": {
            "description": "Property Z",
            "type": "string",
            "default": ""
        }
    },
    "required": [
        "propertyX"
    ],
    "additonalProperties": false
}
import os
import json
import jsonschema


SCHEMA_BASE = os.path.join(os.path.abspath(os.path.dirname(__file__)))


def load_json_schema(schema_file_name):
    file_name = f"{schema_file_name}.json"
    schema_file_path = os.path.join(
        SCHEMA_BASE,
        file_name,
    )
    with open(schema_file_path, "r") as schema_file:
        schema = json.load(schema_file)

    return schema


def extend_with_default(validator_class):
    """
    Extends a jsonschema validator class to add default values
    for any properties that aren't specified in the json, but
    have defaults.

    See: jsonschema documentation
    """
    validate_properties = validator_class.VALIDATORS["properties"]

    def set_defaults(validator, properties, instance, schema):
        for property_, subschema in properties.items():
            if "default" in subschema and not isinstance(instance, list):
                instance.setdefault(property_, subschema["default"])

        for error in validate_properties(
            validator, properties, instance, schema,
        ):
            yield error

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


def validate_json_with_schema_details(
    json_data,
    schema_file,
):
    """
    Validates the given json against the json schema in
    the given location and adds error details. Returns any
    json errors found, an empty string if the the json is
    valid and there are no errors.
    """
    schema_json = load_json_schema(schema_file)
    base_uri = f"file://{SCHEMA_BASE}/"
    resolver = jsonschema.RefResolver(
        base_uri=base_uri,
        referrer=schema_json,
    )

    DefaultDraft7Validator = extend_with_default(jsonschema.Draft7Validator)
    errors = DefaultDraft7Validator(schema_json, resolver=resolver).iter_errors(json_data)

    return list(errors)


if __name__ == "__main__":

    value = {
        "number": 1,
        "type": "A",
        "extra": {
            "propertyX": True,
        },
    }
    errors = validate_json_with_schema_details(
        value,
        "main_schema",
    )
    print(value)
    print(errors)

Output under version 4.9.0:

(venv) leilas@leila-ubuntu-1191pc:~/workspace$ python validate.py 
{'number': 1, 'type': 'A', 'extra': {'propertyX': True, 'propertyY': None, 'propertyZ': ''}, 'metadata': {}}
[]

Output under version 4.10.3:

(venv) leilas@leila-ubuntu-1191pc:~/workspace$ python validate.py 
{'number': 1, 'type': 'A', 'extra': {'propertyX': True}, 'metadata': {}}
[]
@Julian
Copy link
Member

Julian commented Sep 14, 2023

This looks likely to be a duplicate of #994, have a look there.

@Julian Julian closed this as not planned Won't fix, can't repro, duplicate, stale Sep 14, 2023
@Julian Julian added the Invalid Not a bug, PEBKAC, or an unsupported setup label Feb 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Invalid Not a bug, PEBKAC, or an unsupported setup
Projects
None yet
Development

No branches or pull requests

2 participants