kiln_ai.datamodel.json_schema

 1import json
 2from typing import Annotated, Dict
 3
 4import jsonschema
 5import jsonschema.exceptions
 6import jsonschema.validators
 7from pydantic import AfterValidator
 8
 9JsonObjectSchema = Annotated[
10    str,
11    AfterValidator(lambda v: _check_json_schema(v)),
12]
13"""A pydantic type that validates strings containing JSON schema definitions.
14Must be a valid JSON schema object with 'type': 'object' and 'properties' defined.
15"""
16
17
18def _check_json_schema(v: str) -> str:
19    """Internal validation function for JSON schema strings.
20
21    Args:
22        v: String containing a JSON schema definition
23
24    Returns:
25        The input string if valid
26
27    Raises:
28        ValueError: If the schema is invalid
29    """
30    schema_from_json_str(v)
31    return v
32
33
34def validate_schema(instance: Dict, schema_str: str) -> None:
35    """Validate a dictionary against a JSON schema.
36
37    Args:
38        instance: Dictionary to validate
39        schema_str: JSON schema string to validate against
40
41    Raises:
42        jsonschema.exceptions.ValidationError: If validation fails
43        ValueError: If the schema is invalid
44    """
45    schema = schema_from_json_str(schema_str)
46    v = jsonschema.Draft202012Validator(schema)
47    return v.validate(instance)
48
49
50def schema_from_json_str(v: str) -> Dict:
51    """Parse and validate a JSON schema string.
52
53    Args:
54        v: String containing a JSON schema definition
55
56    Returns:
57        Dict containing the parsed JSON schema
58
59    Raises:
60        ValueError: If the input is not a valid JSON schema object with required properties
61    """
62    try:
63        parsed = json.loads(v)
64        jsonschema.Draft202012Validator.check_schema(parsed)
65        if not isinstance(parsed, dict):
66            raise ValueError(f"JSON schema must be a dict, not {type(parsed)}")
67        # Top level arrays are valid JSON schemas, but we don't want to allow them here as they often cause issues
68        if (
69            "type" not in parsed
70            or parsed["type"] != "object"
71            or "properties" not in parsed
72        ):
73            raise ValueError(f"JSON schema must be an object with properties: {v}")
74        return parsed
75    except jsonschema.exceptions.SchemaError as e:
76        raise ValueError(f"Invalid JSON schema: {v} \n{e}")
77    except json.JSONDecodeError as e:
78        raise ValueError(f"Invalid JSON: {v}\n {e}")
79    except Exception as e:
80        raise ValueError(f"Unexpected error parsing JSON schema: {v}\n {e}")
JsonObjectSchema = typing.Annotated[str, AfterValidator(func=<function <lambda>>)]

A pydantic type that validates strings containing JSON schema definitions. Must be a valid JSON schema object with 'type': 'object' and 'properties' defined.

def validate_schema(instance: Dict, schema_str: str) -> None:
35def validate_schema(instance: Dict, schema_str: str) -> None:
36    """Validate a dictionary against a JSON schema.
37
38    Args:
39        instance: Dictionary to validate
40        schema_str: JSON schema string to validate against
41
42    Raises:
43        jsonschema.exceptions.ValidationError: If validation fails
44        ValueError: If the schema is invalid
45    """
46    schema = schema_from_json_str(schema_str)
47    v = jsonschema.Draft202012Validator(schema)
48    return v.validate(instance)

Validate a dictionary against a JSON schema.

Args: instance: Dictionary to validate schema_str: JSON schema string to validate against

Raises: jsonschema.exceptions.ValidationError: If validation fails ValueError: If the schema is invalid

def schema_from_json_str(v: str) -> Dict:
51def schema_from_json_str(v: str) -> Dict:
52    """Parse and validate a JSON schema string.
53
54    Args:
55        v: String containing a JSON schema definition
56
57    Returns:
58        Dict containing the parsed JSON schema
59
60    Raises:
61        ValueError: If the input is not a valid JSON schema object with required properties
62    """
63    try:
64        parsed = json.loads(v)
65        jsonschema.Draft202012Validator.check_schema(parsed)
66        if not isinstance(parsed, dict):
67            raise ValueError(f"JSON schema must be a dict, not {type(parsed)}")
68        # Top level arrays are valid JSON schemas, but we don't want to allow them here as they often cause issues
69        if (
70            "type" not in parsed
71            or parsed["type"] != "object"
72            or "properties" not in parsed
73        ):
74            raise ValueError(f"JSON schema must be an object with properties: {v}")
75        return parsed
76    except jsonschema.exceptions.SchemaError as e:
77        raise ValueError(f"Invalid JSON schema: {v} \n{e}")
78    except json.JSONDecodeError as e:
79        raise ValueError(f"Invalid JSON: {v}\n {e}")
80    except Exception as e:
81        raise ValueError(f"Unexpected error parsing JSON schema: {v}\n {e}")

Parse and validate a JSON schema string.

Args: v: String containing a JSON schema definition

Returns: Dict containing the parsed JSON schema

Raises: ValueError: If the input is not a valid JSON schema object with required properties