I'm using a slightly modified version of the code from the JSON Schema FAQ to create a validator that sets default values:
def extend_with_default(validator_class):
validate_properties = validator_class.VALIDATORS["properties"]
def set_defaults(validator, properties, instance, schema):
for property_, subschema in properties.items():
if "default" in subschema:
instance.setdefault(property_, subschema["default"])
for error in validate_properties(
validator, properties, instance, schema,
):
yield error
return validators.extend(
validator_class, {"properties": set_defaults},
)
DefaultValidatingDraft4Validator = extend_with_default(Draft4Validator)
And I have a JSON Schema like so:
{'definitions': {
'obj': {'additionalProperties': False,
'properties': {
'foo': {'default': None, 'oneOf': [{'type': 'null'}, {'type': 'string'}]},
'bar': {'default': None, 'oneOf': [{'type': 'null'}, {'type': 'string'}]},
'baz': {'default': None, 'oneOf': [{'type': 'null'}, {'type': 'string'}]},
'children': {'default': None, 'oneOf': [
{'type': 'null'},
{
'items': {'$ref': '#/definitions/obj'},
'minItems': 1,
'type': 'array'
}
]}},
'required': ['foo', 'bar', 'baz'],
'type': 'object'}},
'oneOf': [
{'$ref': '#/definitions/obj'},
{
'items': {'$ref': '#/definitions/obj'},
'minItems': 1,
'type': 'array'
}
]
}
So basically, there's an object that can have foo/bar/baz
fields, and the entire instance can either be one of those objects or a list of them. Additionally, each object can have a list of child objects in the children
field.
When I try to run this code against a single object, it works fine, but it fails when I have a list of objects:
In [22]: DefaultValidatingDraft4Validator(schema).validate({'foo': 'hi'})
In [23]: DefaultValidatingDraft4Validator(schema).validate([{'foo': 'hi'}, {'baz': 'bye'}])
...
AttributeError: 'list' object has no attribute 'setdefault'
With the "children" field, I need a way to handle lists at every level of the schema validation. Is there a way to do that properly?