解析和验证YAML配置文件的最佳方式
问题描述:
我们有一个项目,它将设置存储在YAML中(设置文件由可执行脚本生成)。现在我们使用pyyaml来解析YAML格式和棉花糖来验证设置。我很喜欢在YAML中存储设置,但我不认为marshmellow是我需要的工具(模式很难阅读,我不需要序列化设置,想要像xsd)。那么在项目中验证设置的最佳实践是什么,也许有语言独立的方式? (我们使用Python 2.7)解析和验证YAML配置文件的最佳方式
YAML设置:
successive:
worker:
cds_process_number: 0 # positive integer or zero
spider_interval: 10 # positive integer
run_worker_sh: /home/lmakeev/CDS/releases/master/scripts/run_worker.sh # OS path
allow:
- "*" # regular expression
deny:
- "^[A-Z]{3}_.+$" # regular expression
答
一个模式描述是它自己的语言,用它自己的语法,你必须学会的特质。如果您的要求发生变化,您必须维护您的YAML所针对的“程序”。
如果您已经在使用YAML并熟悉Python,则可以使用YAML的标记工具在分析时检查对象。
假设你有一个文件input.yaml
:
successive:
worker:
cds_process_number: !nonneg 0
spider_interval: !pos 10
run_worker_sh: !path /home/lmakeev/CDS/releases/master/scripts/run_worker.sh
allow:
- !regex "*"
deny:
- !regex "^[A-Z]{3}_.+$"
,您可以创建并注册使用以下program¹是检查值的四个班(除去和标签插入评论您的示例文件):
import sys
import os
import re
import ruamel.yaml
import pathlib
class NonNeg:
yaml_tag = u"!nonneg"
@classmethod
def from_yaml(cls, constructor, node):
val = int(node.value) # this creates/returns an int
assert val >= 0
return val
class Pos(int):
yaml_tag = u"!pos"
@classmethod
def from_yaml(cls, constructor, node):
val = cls(node.value) # this creates/return a Pos()
assert val > 0
return val
class Path:
yaml_tag = u"!path"
@classmethod
def from_yaml(cls, constructor, node):
val = pathlib.Path(node.value)
assert os.path.exists(val)
return val
class Regex:
yaml_tag = u"!regex"
def __init__(self, val, comp):
# store original string and compile() of that string
self._val = val
self._compiled = comp
@classmethod
def from_yaml(cls, constructor, node):
val = str(node.value)
try:
comp = re.compile(val)
except Exception as e:
comp = None
print("Incorrect regex", node.start_mark)
print(" ", node.tag, node.value)
return cls(val, comp)
yaml = ruamel.yaml.YAML(typ="safe")
yaml.register_class(NonNeg)
yaml.register_class(Pos)
yaml.register_class(Path)
yaml.register_class(Regex)
data = yaml.load(pathlib.Path('input.yaml'))
个人from_yaml
classmethods中的实际检查应该适合您的需要(我必须删除Path的断言,因为我没有该文件)。
如果你运行上面的你会注意它打印:
Incorrect regex in "input.yaml", line 7, column 9
!regex *
因为"*"
不是有效的正则表达式。您的意思是:".*"
?
¹这是使用ruamel.yaml,一个YAML 1.2分析器,其中我的作者来完成。您可以使用PyYAML实现相同的结果,例如通过子类化ObjectDict
(默认情况下不安全,因此请确保在代码中正确)
可能会详细说明一点。你为什么认为棉花糖不是正确的工具?现在这是非常开放的。 – Grimmy
由于非常复杂的结构架构难以阅读,我不需要序列化的设置,想要的东西像xsd – Helvdan
这样的事情?:https://github.com/Julian/jsonschema – Grimmy