校验与诊断¶
校验由 Provider 负责,引擎只负责调用和汇总。所有问题会一次性收集,而不是 遇到第一个错误就停止。Provider 契约见 Provider 参考与开发。
Diagnostic¶
from devconfig_gen import Diagnostic
d = Diagnostic("app.port", "port must be between 1 and 65535, got 99999")
str(d) # "port must be between 1 and 65535, got 99999"
d.severity # "error"(默认);也可以是 "warning"
d.as_dict() # {"field": "app.port", "message": "...", "severity": "error"}
field:出问题值的点路径(如app.port);未知路径时为"";message:已渲染的用户可读文本;severity:"error"或"warning"。
validate 与 diagnose¶
Provider 必须实现 validate(request) -> Sequence[str],返回渲染后的消息。
推荐同时实现 diagnose(request) -> Sequence[Diagnostic] 以获得结构化字段
路径;未实现时引擎自动把 validate 的消息包装为 field="" 的
Diagnostic:
from devconfig_gen import diagnose_request, validate_request
validate_request("env", context={}) # ("variables must not be empty",)
diagnose_request("env", context={}) # (Diagnostic(field="variables", ...),)
两者都不生成产物、不写文件。
引擎的失败方式¶
engine.generate先调用validate;只要有错误,就把消息用"; "拼接后 抛出ValueError;- Provider 的
generate通常也会自行校验,失败时抛出ValidationError(ValueError的子类,见下); - 因此调用方只需捕获
ValueError即可处理两类失败。
CLI 行为¶
devconfig-gen validate --provider env --input broken.yaml
# stderr: invalid: variables must not be empty
# 退出码 1
- 默认只向 stderr 打印
error级别的消息;通过时 stdout 输出<输入路径列表>: valid; --json改为向 stdout 打印全部诊断(含 warning)的 JSON 数组;- 退出码只看
error:有 error 为1,否则0; - 加载、解析、未知 Provider 等错误不属于诊断,直接
error: ...到 stderr, 退出码2。
内置 Provider 当前只会产生 error 级诊断;warning 是数据模型支持的级别,
第三方 Provider 可以使用。
校验辅助函数¶
devconfig_gen.validation 提供一组路径感知的原语。每个函数把
Diagnostic 追加到传入的 errors 列表,并返回规范化后的值(失败返回
None),从而一次收集全部问题。消息使用路径的叶子名,field 保留完整
点路径。
| 函数 | 行为 |
|---|---|
expect_mapping(value, path, errors) |
必须是映射,否则 <leaf> must be a mapping, got ... |
expect_string(value, path, errors, *, allow_empty=False) |
必须是字符串;去除首尾空白;默认不允许空串 |
expect_integer(value, path, errors, *, minimum=None, maximum=None) |
必须是整数(bool 被拒绝);支持单边或双边范围 |
expect_enum(value, path, errors, *, allowed, case_insensitive=True) |
必须命中选项;默认忽略大小写并返回规范选项 |
expect_string_mapping(value, path, errors) |
值为标量的映射;值规范化为字符串(None→"");嵌套容器报错 |
辅助判断:is_mapping、is_integer(排除 bool)。
from devconfig_gen import validation
errors = []
validation.expect_integer(99999, "app.port", errors, minimum=1, maximum=65535)
# errors == [Diagnostic("app.port", "port must be between 1 and 65535, got 99999")]
ValidationError¶
from devconfig_gen import Diagnostic, ValidationError
err = ValidationError([Diagnostic("a", "a is bad"), "b: two"])
err.errors # ("a is bad", "b: two")
err.diagnostics # (Diagnostic("a", "a is bad"), Diagnostic("", "b: two"))
str(err) # "a is bad; b: two"
ValidationError 接受 Diagnostic 或字符串序列,并把字符串包装为
field="" 的诊断。它继承 ValueError,因此 engine.generate 与 CLI 的
错误处理路径一致。
内置 Provider 的诊断示例¶
from devconfig_gen import diagnose_request
# env:空变量映射
diagnose_request("env", context={})
# [Diagnostic(field="variables", message="variables must not be empty")]
# env:列表包含映射
diagnose_request("env", context={"b": [{"x": 1}]})
# [Diagnostic(field="b", message="b must not contain mappings")]
# json:根不是映射
diagnose_request("json", context=[1, 2, 3])
# [Diagnostic(field="", message="document: expected a mapping at the root")]
# custom:永远通过
diagnose_request("custom", context={"anything": [1, 2]})
# ()
更多内容见 Python API 与 Provider 参考与开发。