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

Hel*_*dan 5 python settings yaml python-2.7

我们有一个在 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
Run Code Online (Sandbox Code Playgroud)

Ant*_*hon 3

模式描述是一种它自己的语言,有它自己的语法和特性,你必须学习。如果您的需求发生变化,您必须维护其“程序”,以验证您的 YAML。

\n\n

如果您已经在使用 YAML 并且熟悉 Python,则可以使用 YAML 的标记工具在解析时检查对象。

\n\n

假设您有一个文件input.yaml

\n\n
successive:\n  worker:\n    cds_process_number: !nonneg 0\n    spider_interval: !pos 10\n    run_worker_sh: !path /home/lmakeev/CDS/releases/master/scripts/run_worker.sh\n    allow:\n      - !regex "*"\n    deny:\n      - !regex "^[A-Z]{3}_.+$"\n
Run Code Online (Sandbox Code Playgroud)\n\n

(您的示例文件已删除注释并插入标签),您可以使用以下程序创建并注册四个类来检查值\xc2\xb9:

\n\n
import sys\nimport os\nimport re\nimport ruamel.yaml\nimport pathlib\n\nclass NonNeg:\n    yaml_tag = u"!nonneg"\n\n    @classmethod\n    def from_yaml(cls, constructor, node):\n        val = int(node.value)   # this creates/returns an int\n        assert val >= 0\n        return val\n\nclass Pos(int):\n    yaml_tag = u"!pos"\n\n    @classmethod\n    def from_yaml(cls, constructor, node):\n        val = cls(node.value)  # this creates/return a Pos()\n        assert val > 0\n        return val\n\nclass Path:\n    yaml_tag = u"!path"\n\n    @classmethod\n    def from_yaml(cls, constructor, node):\n        val = pathlib.Path(node.value)\n        assert os.path.exists(val)\n        return val\n\n\nclass Regex:\n    yaml_tag = u"!regex"\n    def __init__(self, val, comp):\n        # store original string and compile() of that string\n        self._val = val\n        self._compiled = comp\n\n    @classmethod\n    def from_yaml(cls, constructor, node):\n        val = str(node.value)\n        try:\n            comp = re.compile(val)\n        except Exception as e:\n            comp = None\n            print("Incorrect regex", node.start_mark)\n            print("  ", node.tag, node.value)\n        return cls(val, comp)\n\n\nyaml = ruamel.yaml.YAML(typ="safe")\nyaml.register_class(NonNeg)\nyaml.register_class(Pos)\nyaml.register_class(Path)\nyaml.register_class(Regex)\n\ndata = yaml.load(pathlib.Path(\'input.yaml\'))\n
Run Code Online (Sandbox Code Playgroud)\n\n

各个类方法中的实际检查from_yaml应该适应您的需求(我必须删除路径的断言,因为我没有该文件)。

\n\n

如果您运行上面的代码,您会注意到它打印:

\n\n
Incorrect regex   in "input.yaml", line 7, column 9\n   !regex *\n
Run Code Online (Sandbox Code Playgroud)\n\n

因为"*"不是有效的正则表达式。你的意思:".*"

\n\n
\n\n

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

\n