【问题标题】:the best way to parse and validate YAML configuration file解析和验证 YAML 配置文件的最佳方法
【发布时间】:2017-12-22 04:48:26
【问题描述】:

我们有在 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

【问题讨论】:

  • 也许可以再详细一点。为什么你认为棉花糖不是正确的工具?现在这是非常开放的。
  • 由于非常复杂的结构模式难以阅读,我不需要序列化设置,想要 xsd 之类的东西
  • 我应该考虑使用 JSON。没有 YAML 的解决方案吗?
  • @Anthon,我用 YAML 设置示例更新了这个问题。

标签: python python-2.7 yaml settings


【解决方案1】:

模式描述是它自己的语言,有它自己的语法和你必须学习的特性。如果您的要求发生变化,您必须维护其验证 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}_.+$"

(您的示例文件删除了 cmets 并插入了标签),您可以使用以下程序创建和注册四个检查值的类¹:

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

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

Incorrect regex   in "input.yaml", line 7, column 9
   !regex *

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


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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-06
    相关资源
    最近更新 更多