我使用voluptuous了很多來驗證 yaml 描述檔案。通常這些錯誤很難破譯,尤其是對于普通用戶而言。
我正在尋找一種使錯誤更具可讀性的方法。一種方法是識別 YAML 檔案中的哪一行是有罪的。
from voluptuous import Schema
import yaml
from io import StringIO
Validate = Schema({
'name': str,
'age': int,
})
data = """
name: John
age: oops
"""
data = Validate(yaml.load(StringIO(data)))
在上面的示例中,我收到此錯誤:
MultipleInvalid: expected int for dictionary value @ data['age']
我寧愿喜歡這樣的錯誤:
Error: validation failed on line 2, data.age should be an integer.
有沒有一種優雅的方式來實作這一目標?
uj5u.com熱心網友回復:
問題在于,在 的 API 邊界上yaml.load,源的所有代表性資訊都已丟失。Validate得到一個 Python dict 并且不知道它來自哪里,而且 dict 不包含此資訊。
但是,您可以自己實作它。voluptuous'Invalid錯誤帶有一個path要遵循的鍵串列。有了這個路徑,您可以再次將 YAML 決議為節點(攜帶表示資訊)并發現專案的位置:
import yaml
def line_from(path, yaml_input):
node = yaml.compose(yaml_input)
for item in path:
for entry in node.value:
if entry[0].value == item:
node = entry[1]
break
else: raise ValueError("unknown path element: " item)
return node.start_mark.line
# demostrating this on more complex input than yours
data = """
spam:
egg:
sausage:
spam
"""
print(line_from(["spam", "egg", "sausage"], data))
# gives 4
有了這個,你就可以做到
try:
data = Validate(yaml.load(StringIO(data)))
except Invalid as e:
line = line_from(e.path, data)
path = "data." ".".join(e.path)
print(f"Error: validation failed on line {line} ({path}): {e.error_message}")
我會為這個答案走這么遠,因為它向您展示了如何發現錯誤的起源行。您可能需要將其擴展到:
- 處理 YAML 序列(我的代碼假設每個中間節點都是 a
MappingNode, aSequenceNode將在其串列中有單個節點value而不是鍵值元組) MultipleInvalid為每個內部錯誤發出訊息的句柄expected int如果你真的想重寫should be an integer(不知道你會怎么做)- 列印錯誤后中止
uj5u.com熱心網友回復:
在flyx的幫助下,我發現ruamel.yaml它提供了決議的 YAML 檔案的行和列。因此,可以通過以下方式設法獲得所需的錯誤:
from voluptuous import Schema
from ruamel.yaml import load, RoundTripLoader
from io import StringIO
Validate = Schema({
'name': {
'firstname': str,
'lastname': str
},
'age': int,
})
data = """
name:
firstname: John
lastname: 12.0
age: 42
"""
class Validate:
def __init__(self, stream):
self._yaml = load(stream, Loader=RoundTripLoader)
return self.validate()
def validate(self):
try:
self.data = Criteria(self._yaml)
except Invalid as e:
node = self._yaml
for key in e.path:
if (hasattr(node[key], '_yaml_line_col')):
node = node[key]
else:
break
path = '/'.join(e.path)
print(f"Error: validation failed on line {node._yaml_line_col.line}:{node._yaml_line_col.col} (/{path}): {e.error_message}")
else:
return self.data
data = Validate(StringIO(data))
有了這個我得到這個錯誤資訊:
Error: validation failed on line 2:4 (/name): extra keys not allowed
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/425406.html
