DEBUG.WIKI
OnlineSIM:在线接收短信,虚拟号码租用
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
RackNerd;$21.99/年 · 1GB KVM

jsonschema 校验正则报 ASCII and UNICODE flags are incompatible

jsonschema 4.26.0 的 regex checker 只转换 re.error,冲突标志会泄漏 ValueError。给专用 FormatChecker 补实例级异常契约,保留字符串类型与正则成本边界。

FormatChecker.conforms() 对普通坏正则返回 False,遇到 (?u)(?a) 却把 ValueError: ASCII and UNICODE flags are incompatible 抛到接口外面。使用 jsonschema 4.26.0 时,这与内置 regex checker 声明捕获的异常范围有关。

该 checker 调用 Python 的 re.compile(),只声明将 re.error 转成格式错误。两个分开的、不兼容的 Unicode 与 ASCII 标志组会触发 ValueError,它不是 re.error 的子类,因此绕过了这层转换。不能由“用了 FormatChecker”推断任意正则输入都会变成普通校验失败。

在专用 checker 实例上补齐这条异常分支

对确实以 Python re 为匹配引擎的应用,可为这个校验入口使用独立实例,明确覆盖不兼容标志产生的 ValueError:

import re
from jsonschema import Draft202012Validator, FormatChecker

checker = FormatChecker()

@checker.checks("regex", raises=(re.error, ValueError))
def is_python_regex(value):
    if not isinstance(value, str):
        return True
    re.compile(value)
    return True

schema = {"type": "string", "format": "regex"}
validator = Draft202012Validator(schema, format_checker=checker)

这是实例级覆盖,避免修改其他调用方共享的默认格式表。后续应通过这个 validator 的 iter_errors() 等原有入口消费结果;创建了 checker 却没有传入 validator,不会改变实际校验。

非字符串直接返回 True 是格式 checker 的职责边界,字符串类型要求由 schema 中的 type 承担。不要删除 type 后误以为格式校验会替它拒绝数字或对象。

这项覆盖沿用内置 checker 的 Python 正则语法。若数据契约要求另一种正则方言,应使用对应引擎与规则,不能只因为 Python 能编译,就宣布它符合任意 JSON Schema 使用场景。

异常被转换,不代表正则已经安全

当前修改针对冲突标志的 ValueError。深度嵌套和超大重复次数还可能触发其他异常,不应扩大到捕获所有 Exception 再一概返回“格式不合法”,掩盖校验器自身的程序错误。

外部模式应有应用自己的长度、嵌套或功能限制。re.compile() 成功只说明能编译,不保证随后拿它匹配文本时没有高成本回溯;仅捕获这次异常不能解决正则拒绝服务风险。

检查时保留有效模式、未闭合方括号以及两种冲突标志顺序。有效输入仍应通过,无效输入应进入原来的校验错误响应,不能让服务返回成功或空结果。不要为了“验证异常”在生产接口提交超深或超长模式。

未来改用其他正式版本时,核对内置 checker 的实际异常契约,再决定是否撤除实例覆盖。没有明确的已发布修正前,不能只按版本号变大就删除这条输入边界。