Python 解析和验证YAML配置文件的最佳方法

Python 解析和验证YAML配置文件的最佳方法,python,python-2.7,yaml,settings,Python,Python 2.7,Yaml,Settings,我们有一个在YAML中存储设置的项目(设置文件由ansible脚本生成)。现在,我们使用pyyaml解析YAML格式,使用marshmallow验证设置。我很乐意将设置存储在YAML中,但我不认为marshmellow是我需要的工具(模式很难阅读,我不需要设置序列化,需要类似xsd的东西)。那个么,在项目中验证设置的最佳实践是什么呢?也许有一种独立于语言的方式?(我们正在使用python 2.7) YAML设置: successive: worker: cds_process_num

我们有一个在YAML中存储设置的项目(设置文件由ansible脚本生成)。现在,我们使用pyyaml解析YAML格式,使用marshmallow验证设置。我很乐意将设置存储在YAML中,但我不认为marshmellow是我需要的工具(模式很难阅读,我不需要设置序列化,需要类似xsd的东西)。那个么,在项目中验证设置的最佳实践是什么呢?也许有一种独立于语言的方式?(我们正在使用python 2.7)

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}_.+$"
(删除注释并插入标记的示例文件),您可以创建并注册四个类,使用以下程序检查值:

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'))
_yamlclassmethods中单个
中的实际检查应该适合您的需要(我必须删除路径的断言,因为我没有该文件)

如果运行上述命令,您会注意到它会打印:

Incorrect regex   in "input.yaml", line 7, column 9
   !regex *
因为
“*”
不是有效的正则表达式。你的意思是:
“*”



这是使用YAML 1.2解析器完成的,我是该解析器的作者。您可以使用PyYAML获得相同的结果,例如通过子类化
ObjectDict
(默认情况下这是不安全的,因此请确保在代码中更正它)

可能需要详细说明一下。为什么你认为棉花糖不是合适的工具?现在这是非常开放的。由于非常复杂的结构模式很难阅读,我不需要序列化设置,想要像xsdSomething这样的东西吗?:我应该考虑使用JSON。但是YAML没有解决方案吗?@Anthon,我用YAML设置示例更新了这个问题。