尝试在Python中使JSON模式验证器设置默认值

2024-09-24 22:19:02 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用JSON Schema FAQ中代码的稍微修改版本来创建一个设置默认值的验证器:

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)

我有这样一个JSON模式:

^{pr2}$

所以基本上,有一个对象可以有foo/bar/baz字段,整个实例可以是其中一个对象,也可以是它们的一个列表。另外,每个对象在children字段中可以有一个子对象列表。在

当我对一个对象的列表运行失败时,当我对它运行一个很好的对象时:

In [22]: DefaultValidatingDraft4Validator(schema).validate({'foo': 'hi'})

In [23]: DefaultValidatingDraft4Validator(schema).validate([{'foo': 'hi'}, {'baz': 'bye'}])

...
AttributeError: 'list' object has no attribute 'setdefault'

对于“children”字段,我需要一种在模式验证的每个级别处理列表的方法。有没有一种方法可以正确地做到这一点?在


Tags: 对象instanceinjsondefault列表fooschema
1条回答
网友
1楼 · 发布于 2024-09-24 22:19:02

在验证器中,导致异常的list是有效元素。在

需要更改:

因此,您需要通过更改以下内容将list排除在考虑范围之外:

if "default" in subschema:
    instance.setdefault(property_, subschema["default"])

收件人:

^{pr2}$

这就是让两个测试用例通过所需的全部内容。在

代码:

from jsonschema import Draft4Validator, validators


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 and not isinstance(instance, list):
                instance.setdefault(property_, subschema["default"])

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

    return validators.extend(
        validator_class, {"properties": set_defaults},
    )
FillDefaultValidatingDraft4Validator = extend_with_default(Draft4Validator)

测试代码:

test_schema = {
    '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'
        }
    ]
}

for test_data in ({'foo': 'hi'}, [{'foo': 'hi'}, {'baz': 'bye'}], 
                  [{'children': [{'foo': 'hi'}, {'baz': 'bye'}]}]):
    FillDefaultValidatingDraft4Validator(test_schema).validate(test_data)
    print(test_data)

结果:

{'foo': 'hi', 'bar': None, 'baz': None, 'children': None}
[
    {'foo': 'hi', 'bar': None, 'baz': None, 'children': None}, 
    {'baz': 'bye', 'foo': None, 'bar': None, 'children': None}
]
[
    {'children': [
        {'foo': 'hi', 'bar': None, 'baz': None, 'children': None}, 
        {'baz': 'bye', 'foo': None, 'bar': None, 'children': None}
    ], 'foo': None, 'bar': None, 'baz': None}
]

相关问题 更多 >