【问题标题】:Trying to make JSON Schema validator in Python to set default values尝试在 Python 中制作 JSON Schema 验证器来设置默认值
【发布时间】:2016-12-22 19:57:49
【问题描述】:

我正在使用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 架构:

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

所以基本上,有一个对象可以有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”字段,我需要一种方法来处理架构验证的每个级别的列表。有没有办法正确地做到这一点?

【问题讨论】:

    标签: python jsonschema


    【解决方案1】:

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

    需要改变:

    因此,您需要通过更改将list 排除在考虑之外:

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

    到:

    if "default" in subschema and not isinstance(instance, list):
        instance.setdefault(property_, subschema["default"])
    

    这就是让两个测试用例通过所需要的一切。

    代码:

    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}
    ]
    

    【讨论】:

      猜你喜欢
      • 2017-08-17
      • 2015-11-18
      • 2021-02-08
      • 1970-01-01
      • 1970-01-01
      • 2018-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多