当前位置: 首页 > 工具软件 > jsonschema > 使用案例 >

Python的jsonschema模块详解

燕昊东
2023-12-01

简介

jsonschemaJSON Schema 的Python实现(支持Python 2.7+ 包括Python3)。

>>> from jsonschema import validate

>>> # A sample schema, like what we'd get from json.load()
>>> schema = {
...     "type" : "object",
...     "properties" : {
...         "price" : {"type" : "number"},
...         "name" : {"type" : "string"},
...     },
... }

>>> # If no exception is raised by validate(), the instance is valid.
>>> validate(instance={"name" : "Eggs", "price" : 34.99}, schema=schema)

>>> validate(
...     instance={"name" : "Eggs", "price" : "Invalid"}, schema=schema,
... )                                   
Traceback (most recent call last):
    ...
ValidationError: 'Invalid' is not of type 'number'

功能

  • 完全支持 Draft 7Draft 6Draft 4Draft 3
  • 延迟验证,可以迭代地报告所有验证错误。
  • 可以以编程方式查询哪些属性或项验证失败。

安装

可以通过 pip 直接安装:

$ pip install jsonschema

API详解

模式验证

基础用法

在给定模式下验证JSON实例的最简单方法是使用 validate() 函数。

jsonschema.validate(instance, schema, cls=None, *args, **kwargs)

在给定的模式下验证JSON实例:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/neochen/.virtualenvs/Test/lib/python3.7/site-packages/jsonschema/validators.py", line 899, in validate
    raise error
jsonschema.exceptions.ValidationError: [1, 2, 3] is too long

Failed validating 'maxItems' in schema:
    {'maxItems': 2}

On instance:
    [1, 2, 3]

validate() 函数将首先验证所提供的模式本身是否有效,因为不这样做会导致不太明显的错误消息,并以不太明显或一致的方式失败。

如果想要用一个有效的模式验证多个实例,可以在一个特定的验证器上直接使用 IValidator.validate() 方法(例如,Draft7Validator.validate())。

参数

  • instance:要验证的JSON实例
  • schema:要使用的模式
  • clsIValidator):被用来验证JSON实例的验证器类

如果 cls 参数未提供,按照规范,将会发生两件事。首先,如果模式具有包含已知元模式1$schema 属性,那么将使用适当的验证器。由于这个原因,规范建议所有模式都包含 $schema 属性。如果没有找到 $schema 属性,则使用最新发布的草案作为验证器类。关于创建JSON模式来验证数据,有一篇很好的介绍JSON模式基础知识的文章 《理解JSON模式》。

在实例化 cls 时,将传递提供的所有的位置参数和关键字参数。

异常

  • 如果JSON实例是无效的,则抛出 jsonschema.exceptions.ValidationError 异常
  • 如果模式本身是无效的,则抛出 jsonschema.exceptions.SchemaError 异常

验证器接口

jsonschema 定义了一个所有验证器类都应该遵守的(非正式的)接口。

class jsonschema.IValidator(schema, types=(), resolver=None, format_checker=None)

  • 参数:

    • schema (dict)

      验证器对象将使用的模式。这个模式被假定为有效的,如果提供一个了无效的模式可能会导致未定义的行为。要了解如何验证模式本身,请查看 IValidator.check_schema

    • resolver

      用于解析 $ref 属性(JSON引用)的 RefResolver 实例。如果未提供,则会创建一个。

    • format_checker

      一个 FormatChecker 实例。其中,FormatChecker.conforms 方法用来验证JSON实例是否符合模式中出现的每一个格式属性。如果未提供,则不会对格式进行验证。某些格式需要安装额外的包(IPv6、URI、颜色、日期-时间)。所需的软件包可以在本页底部找到。

    • types

      从 3.0.0 版本开始弃用:使用 TypeChecker.readfinejsonschema.validators.extend 代替这个参数。

      要了解更多细节,请查看 Validating With Additional Types

      如果使用了这个参数,在验证 type 属性时,它将覆盖或拓展已知类型列表。

      这个参数的值应该是表示类型名称的字符串到将要通过 isinstance 方法来进行验证的类对象的映射。

  • META_SCHEMA

    表示验证器的元模式的对象(在给定版本中描述有效模式的模式)。

  • VALIDATORS

    验证器名称(字符串类型)到用该名称验证验证器属性的函数的映射。有关更多信息,请参见 [创建或扩展验证器类](Creating or Extending Validator Classes)。

  • TYPE_CHECKER

    一个用于验证JSON模式中 type 属性的 TypeChecker 对象。

  • schema

    初始化对象时传入的模式。

  • DEFAULT_TYPES

    自3.0.0版本以来一直不推荐使用此属性,而是支持使用新的 type 检查器。

    要了解更多细节,请查看 Validating With Additional Types

    为了在现有验证器类上向后兼容,将JSON类型映射到Python类对象,这些对象为每个JSON类型定义Python类型。

    任何使用此属性的现有代码都应该转换为使用 TypeChecker.is_type

  • classmethod check_schema(schema)

    根据验证器的 META_SCHEMA 验证给定的模式。

    如果模式无效,则会引发 jsonschema.exceptions.SchemaError 异常。

  • is_type(instance, type)

    检查实例是否是给定的(JSON模式)类型。

    返回值为布尔类型。

    如果 type 不是已知的类型,则会引发 jsonschema.exceptions.UnknownType 异常。

  • is_valid(instance)

    检查实例在当前模式下是否有效。

    返回值为布尔类型

    >>> schema = {"maxItems" : 2}
    >>> Draft3Validator(schema).is_valid([2, 3, 4])
    False
    
  • iter_errors(instance)

    惰性生成给定实例中的每个验证错误。

    返回值为一个可迭代对象或者 jsonschema.exceptions.ValidationErrors 异常实例。

    >>> schema = {
    ...     "type" : "array",
    ...     "items" : {"enum" : [1, 2, 3]},
    ...     "maxItems" : 2,
    ... }
    >>> v = Draft3Validator(schema)
    >>> for error in sorted(v.iter_errors([2, 3, 4]), key=str):
    ...     print(error.message)
    4 is not one of [1, 2, 3]
    [2, 3, 4] is too long
    
  • validate(instance)

    检查实例在当前模式下是否有效。

    如果实例无效,则会引发 jsonschema.exceptions.ValidationError 异常。

    >>> schema = {"maxItems" : 2}
    >>> Draft3Validator(schema).validate([2, 3, 4])
    Traceback (most recent call last):
        ...
    ValidationError: [2, 3, 4] is too long
    

jsonschema 中包含的所有版本验证器都坚持使用接口,扩展或补充所包含的验证器类的实现人员也应该坚持使用接口。有关更多信息,请参考 [创建或扩展验证器类](Creating or Extending Validator Classes)。

类型检查

为了处理JSON模式的 type 属性,IValidator 使用一个关联的 TypeChecker。类型检查器提供类型名称和函数名称之间的不可变映射,可以测试实例是否属于该类型。默认值适用于大多数用户,jsonschema 中包含的每个版本验证器都有一个 TypeChecker,可以正确处理它们各自的版本。

class jsonschema.TypeChecker(type_checker=pmap(()))

一个 type 属性检查器。

TypeChekcerIValidator 执行类型检查。使用 TypeChecker.redefine 或者 TypeCheker.redefine_many 更新要执行的类型检查,使用 TypeChekcer.remove 移除要执行的类型检查。这些方法均会返回一个新的 TypeChekcer 对象。

参数:type_checkers(dict) :初始的类型和其检查方法的映射。

该类包含如下实例方法:

  • is_type(instance, type)

    检查实例是否属于适当的类型。

    参数:

    • instance (object):要检查的实例
    • type(str):期待的类型名称

    返回类型:布尔类型

    异常:如果实例的类型与 type 参数提供的类型不匹配,则引发 jsonschema.exeptions.UndefinedTypeCheck 异常。

  • redefine(type, fn)

    使用重新定义的给定类型生成一个新的检查器。

    参数:

    • type (str):要检查的类型
    • fn(callable):一个只接受两个参数的函数 — 用于执行检查的函数和要检查的类型。如果实例是这种类型的,函数应该返回 True,否则返回 False

    返回值:一个新的 TypeChecker 实例。

  • redefine_many(definitions=())

    使用重新定义的(多个)给定类型生成一个新的检查器。

    参数:definitions (dict):一个将类型映射到它们对应的检查函数的字典。

    返回值:一个新的 TypeChecker 实例。

  • remove(*types)

    生成一个新的移除了对给定类型进行检查的检查器。

    参数:types (Iterable):要移除的类型名称

    返回值:一个新的新 TypeChecker 实例。

    异常:如果任何给定的任何类型是未知的,则会引发 jsonschema.exceptions.UndefinedTypeCheck 异常。

exceptions jsonschema.exceptions.UndefinedTypeCheck(type)

当试图删除此 TypeChecker 不知道的类型检查或在直接调用 jsonschema.TypeChecker.is_type 时抛出该异常。

使用附加类型进行验证

有时候,在验证JSON模式的 type 属性时,提供附加类型或替代类型可能很有用。

jsonschema 试图在普通情况下的性能和通用性之间取得平衡。例如,JSON模式定义了一个 number 类型,可以使用 {"type": "number"} 之类的模式验证该类型。默认情况下,这个类型将接受Python numbers.Number 的实例。这包括 intfloatdecimal.Decimalcomplex 等。但是,对于 integerobjectjsonschema 只检查 intDictionary displays,而不是检查 numbers.Integeralcollections.abc.Mapping,因为更通用的实例检查可能会导致明显的速度下降,特别是考虑到验证这些类型是多么常见。

如果确实需要通用性,或者只是想添加一些特定的附加类型,以便验证器对象可以接受,那么应该更新现有的TypeChecker 或创建一个新的 TypeChecker。然后,您可以通过 jsonschema.validators.extend 创建一个新的IValidator

class MyInteger(object):
    pass

def is_my_int(checker, instance):
    return (
        Draft3Validator.TYPE_CHECKER.is_type(instance, "number") or
        isinstance(instance, MyInteger)
    )

type_checker = Draft3Validator.TYPE_CHECKER.redefine("number", is_my_int)

CustomValidator = extend(Draft3Validator, type_checker=type_checker)
validator = CustomValidator(schema={"type" : "number"})

exception jasonschema.exceptions.UnknownType(type, instance, schema)

不同版本的验证器

jsonschema 附带各种版本的JSON模式规范的验证器类。有关每个验证器类提供的方法和属性的详细信息,请参见IValidator 接口,其中每个类都包含验证器类的实现。

class jsonschema.Draft7Validator(schema, types=(), resolver=None, format_checker=None)

class jsonschema.Draft7Validator(schema, types=(), resolver=None, format_checker=None)

class jsonschema.Draft7Validator(schema, types=(), resolver=None, format_checker=None)

class jsonschema.Draft7Validator(schema, types=(), resolver=None, format_checker=None)

例如,如果你想验证针对草案6元模式创建的模式,您可以使用:

from jsonschema import Draft6Validator

schema = {
    "$schema": "https://json-schema.org/schema#",

    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "email": {"type": "string"},
    },
    "required": ["email"]
}
Draft6Validator.check_schema(schema)

格式验证

JSON模式定义了 format 属性,该属性可用于检查基本类型(字符串、数字、布尔值)是否符合定义良好的格式。默认情况下,不强制执行验证,但是可以选择将 format -checking 对象连接到 IValidator 来启用验证。

>>> validate("localhost", {"format" : "hostname"})
>>> validate(
...     instance="-12",
...     schema={"format" : "hostname"},
...     format_checker=draft7_format_checker,
... )
Traceback (most recent call last):
    ...
ValidationError: "-12" is not a "hostname"

class jsonschema.FormatChecker(format=None)

一个 format 属性检查器。

JSON模式并不强制 format 属性实际执行任何验证。但是,如果需要验证,可以将该类的实例连接到验证器中,以启用格式验证。

在验证未知的格式时,FormatChecker 对象总是返回 True

要使用接受实例并返回布尔值的函数检查自定义格式,请使用 FormatChecker.checkers 装饰器或 FormatChecker.cls_checks 装饰器。

参数:format (Iterable):要验证的已知格式。此参数可用于限制验证期间将使用哪些格式。

  • classmethod cls_checks(format, raises=())

    注册一个被装饰函数用于全局的新格式的验证。

    调用此函数后创建的任何实例都将获取提供的检查器。

    参数:

    • format (str):被装饰的函数将要检查的格式
    • raises (Exception):当发现无效实例时,被装饰函数引发的异常。exception 对象可以被当作结果验证错误的 jsonschema.exception.ValidationError.cause 属性进行访问。
  • checkers

    将当前已知格式映射到验证它们的函数元组和应该捕获的错误。可以使用 FormatChecker.checksFormatChecker.cls_checks 装饰器分别为每个实例或所有检查器添加或者移除检查器。

  • check(instance, format)

    检查实例是否符合给定的格式。

    参数:

    • instance (所有简单类型,例如 str,number,bool):要检查的实例
    • format (str):实例要符合的格式

    异常:如果实例不符合 format,则会引发 FormatError 异常。

  • checks(format, raises=())

    注册一个被装饰函数用于新格式的验证。

    参数:

    • format (str):被装饰函数要检查的格式
    • raises (Exceptions):当发现无效实例时,被装饰函数引发的异常。exception 对象可以被当作结果验证错误的 jsonschema.exception.ValidationError.cause 属性进行访问。
  • conforms(instance, format)

    检查实例是否符合给定的格式

    参数:

    • instance (所有简单类型,例如 str,number,bool):要检查的实例
    • format (str):实例要符合的格式

    返回值:布尔类型

exception jsonschema.FormatError(message, cause=None)

有许多 FormatCheckers 知道如何进行验证的默认的检查器。可以通过检查 FormatChecker.checkers 属性来查看它们的名称。某些检查器只有在有合适的包可用时才是才可用的。确保您拥有所需包的最简单方法是使用额外的 setuptools format 安装 jsonschema。例如:

$ pip install jsonchema[format]

它将为所有格式安装以下所有依赖项。下面列出了可用检查器的更具体列表,以及它们的需求(如果有的话)。

如果使用需要下面这些包的检查器而没有安装以下包时,将会验证成功而不会引发错误,这是JSON模式规范所指定的。

检查器备注
colorrequires webcolors
date
date-timerequires strict-rfc3339
email
hostname
idn-hostnamerequires idna
ipv4
ipv6OS must have socket.inet_ptonfunction
irirequires rfc3987
iri-referencerequires rfc3987
json-pointerrequires jsonpointer
regex
relative-json-pointerrequires jsonpointer
timerequires strict-rfc3339
urirequires rfc3987
uri-referencerequires rfc3987

因为在大多数情况下,“验证” 电子邮件地址只是一种尝试,而不是确认发送到这个邮件地址的邮件确实会被使用这个邮件地址的收件人成功的接收到。这是因为许多有效的电子邮件地址会在许多地方被错误的拒绝,许多无效的电子邮件地址在许多地方被错误地接受。因而,电子邮件格式验证器只提供了一个完整性检查,而没有提供完整的 rfc5322 验证。

这同样适用于 idn-email 格式。


  1. 被由 jsonschema.validators.validates 注册的验证器所知晓。 ↩︎

 类似资料: