将 oneOf 嵌套在 allOf 中未按预期工作(python jsonschema)

Nesting oneOf inside allOf not working as expected (python jsonschema)

好的,我确定这个 json 架构有问题,但我似乎无法解决这个问题。

我不会 post 实际代码,而是一个重现问题的最小示例。

这是我之前使用的,效果很好:

person = {
    'type': 'object',
    'properties': {
        'name': {
            'type': 'string'
        }
        'auth_token': {
             'type': 'string',
        },
        'username': {
            'type': 'string'
        },
        'password': {
            'type': 'string'
        }
    },
    'oneOf': [
        {
            'required': ['auth_token']
        },
        {
            'required': ['username', 'password']
        }
    ],
    'required': ['name']
}

这里的想法是您始终需要提供此人的姓名,然后是身份验证令牌或用户名和密码对。正如我上面所说,此验证工作正常,因为我们已经参数化测试发送无效 JSON 的所有可能组合并评估生成的错误消息,并且这些测试通过。

但是后来出现了一个新的需求,我需要添加第二个互斥的必填字段对,我是这样做的:

person = {
    'type': 'object',
    'properties': {
        'name': {
            'type': 'string'
        }
        'auth_token': {
             'type': 'string',
        },
        'username': {
            'type': 'string'
        },
        'password': {
            'type': 'string'
        },
        'project_id': {
            'type': 'number'
        },
        'contract_date_from': {
            'type': 'string'
        }
        'contract_date_to': {
            'type': 'string'
        }
    },
    'allOf': [
        {
            'oneOf': [
                {
                    'required': ['auth_token']
                },
                {
                    'required': ['username', 'password']
                }
            ]
        },
        {
            'oneOf': [
                {
                    'required': ['project_id']
                },
                {
                    'required': ['contract_date_from', 'contract_date_to']
                }
            ]
        }
    ],
    'required': ['name']
}

但是现在第二次验证总是失败,不管json提供的是有效还是无效。我收到的错误消息是:

{'name': 'John Doe', 'auth_token': '9d9a324b-26de-4ac3-85eb-05566e4a7204', 'username': None, 'password': None, 'project_id': 2785, 'contract_date_from': None, 'contract_date_to': None} is valid under each of {'required': ['contract_date_from', 'contract_date_to']}, {'required': ['project_id']}

无论我在这三个字段中发送什么值(即项目 ID、合同日期和合同日期),它都会失败并出现相同的错误。我试过将所有三个留空,完成所有三个,以及它们之间的所有排列,但错误保持不变。

我一直在阅读 json 架构的文档,但我似乎无法理解此示例的内容。我正在考虑为此尝试不同的方法,但我真的很想了解为什么这不起作用。感谢您的帮助!

{'name': 'John Doe', 'auth_token': '9d9a324b-26de-4ac3-85eb-05566e4a7204', 'username': None, 'password': None, 'project_id': 2785, 'contract_date_from': None, 'contract_date_to': None} is valid under each of {'required': ['contract_date_from', 'contract_date_to']}, {'required': ['project_id']}

更仔细地阅读错误消息:您请求提供 project_id,或者提供 contract_date_from 和 contract_date_to,但您提供了所有这三个。在 属性 中提供空值仍然提供 属性。错误消息令人困惑,但无论如何您都会失败验证,因为 null 不是字符串。你的评估者只是 运行 allOf->anyOfs 首先,所以这是第一个返回的错误。不过,您仍然应该会遇到类型冲突错误(如果没有,那就是错误:评估者需要提供所有错误,而不仅仅是第一个错误。)

您可以通过将“类型”检查添加到“必需”关键字旁边,以牺牲简洁性为代价来改善错误。这将确保 oneOf 关键字产生失败而不是成功,并可能使错误消息更加明显。