如何使用cerberus获得yaml验证的错误行数?



我正在使用cerberus根据预定义的模式验证我的yaml文件,如下所示

import yaml
schema_text = '''
name:
type: string
age:
type: integer
min: 10
'''
input_text = '''
name: Little Joe                     *(Line 1)*
age: 5                               *(Line 2)*
'''
schema_yaml = yaml.load(schema_text)
input_yaml = yaml.load(input_text)
v.validate(input_yaml , schema_yaml)
v.errors
**{'age': ['min value is 10']}**

在处理YAML验证错误时,不只是向用户显示错误消息,还可以显示验证错误的行号,这样用户就可以弄清楚发生了什么。

  • 例如:

{'age':['最小值为10..发现第2行错误']}

cerberus中有这样的选项吗?任何线索都会很有帮助的。

您应该注意以下几点。首先,你的schema_yaml是无效的YAML单个映射的所有键必须是惟一的. PyYAML将很高兴地加载这种重写stringinteger。您实际上希望获得错误消息,并检测到应该这样做缩进schema_yaml中的一些行。你还应该养成在后面加上反斜杠的习惯开头的三引号,否则字符串以空行开始,然后行号计数将被关闭1。

使用ruamel.yaml(免责声明:我是该软件包的作者),您可以保留在创建映射期间,一个键被分配给的行轨迹。的关键节点的Start_mark具有行号(从0开始):

import sys
import cerberus
import ruamel.yaml
schema_text = '''
name:
type: string
age:
type: integer
min: 10
'''
input_text = '''
name: Little Joe                  #   *(Line 1)*
age: 5                            #   *(Line 2)*
'''
yaml = ruamel.yaml.YAML(typ='safe') # no need for linenumbers in the schema
schema = yaml.load(schema_text)
v = cerberus.Validator()
yaml = ruamel.yaml.YAML()
def my_construct_mapping(self, node, maptyp, deep=False):
if not isinstance(node, ruamel.yaml.nodes.MappingNode):
raise ruamel.yaml.constructor.ConstructorError(
None, None, f'expected a mapping node, but found {node.id!s}', node.start_mark,
)
total_mapping = maptyp
if getattr(node, 'merge', None) is not None:
todo = [(node.merge, False), (node.value, False)]
else:
todo = [(node.value, True)]
for values, check in todo:
mapping = self.yaml_base_dict_type()
for key_node, value_node in values:
# keys can be list -> deep
key = self.construct_object(key_node, deep=True)
# lists are not hashable, but tuples are
if not isinstance(key, Hashable):
if isinstance(key, list):
key = tuple(key)
if not isinstance(key, Hashable):
raise ruamel.yaml.constructor.ConstructorError(
'while constructing a mapping',
node.start_mark,
'found unhashable key',
key_node.start_mark,
)
value = self.construct_object(value_node, deep=deep)
if check:
if self.check_mapping_key(node, key_node, mapping, key, value):
mapping[key] = value
else:
mapping[key] = value
if not hasattr(self.loader, 'keyline'):
self.loader.keyline = {}
self.loader.keyline[key] = key_node.start_mark.line + 1  # ruamel.yaml start line-count at 0
total_mapping.update(mapping)
return total_mapping
yaml.Constructor.construct_mapping = my_construct_mapping

data = yaml.load(input_text)
v.validate(data, schema)
for key, val in v.errors.items():
print(f'error for key "{key}" at line {yaml.keyline[key]}: {"".join(val)}')

给了:

error for key "age" at line 2: min value is 10

最新更新