【问题标题】:Validating a yaml document in python在 python 中验证 yaml 文档
【发布时间】:2011-03-16 19:25:10
【问题描述】:

XML 的一个好处是能够根据 XSD 验证文档。 YAML 没有此功能,那么如何验证我打开的 YAML 文档是否符合我的应用程序预期的格式?

【问题讨论】:

标签: python yaml validation


【解决方案1】:

我不知道 python 解决方案。但是有一个用于 YAML 的 ruby​​ 模式验证器,称为 kwalify。如果你没有遇到 python 库,你应该可以使用 subprocess 访问它。

【讨论】:

  • 我真的在寻找 Pythonic 解决方案。这始终是最后的手段。
【解决方案2】:

试试Rx,它有一个 Python 实现。它适用于 JSON 和 YAML。

来自 Rx 网站:

“向 Web 服务添加 API 时,您必须选择如何对通过线路发送的数据进行编码。XML 是一种常见的选择,但它会很快变得晦涩难懂。很多 Web 服务作者都希望避免考虑 XML,而是选择提供一些简单数据类型的格式,这些数据类型对应于现代编程语言中的常见数据结构,即 JSON 和 YAML。

不幸的是,虽然这些格式可以轻松传递复杂的数据结构,但它们缺乏验证系统。 XML 有 XML Schemas 和 RELAX NG,但这些都是复杂且有时令人困惑的标准。对于 JSON 提供的那种数据结构,它们的可移植性不是很好,如果您想避免使用 XML 作为数据编码,那么编写更多的 XML 来验证第一个 XML 可能就更没有吸引力了。

Rx 旨在提供一个与 JSON 风格的数据结构相匹配的数据验证系统,并且与 JSON 本身一样易于使用。”

【讨论】:

  • 这看起来很有趣。目前尚不清楚它将如何处理以 yaml 编码的 python 对象,但值得一试。
  • 你能分享一些使用例子吗?看了文档但看不懂
  • 自 2014 年以来没有发布 Rx,自 2015 年以来没有提交。
【解决方案3】:

是的 - 支持验证对于许多重要的用例至关重要。参见例如YAML and the importance of Schema Validation « Stuart Gunter

如前所述,Rx 可用于各种语言,Kwalify 可用于 Ruby 和 Java。

另请参阅 PyYAML 讨论:YAMLSchemaDiscussion

一个相关的工作是 JSON Schema,它甚至有一些 IETF 标准化活动:draft-zyp-json-schema-03 - A JSON Media Type for Describing the Structure and Meaning of JSON Documents

【讨论】:

    【解决方案4】:

    这些看起来不错。 yaml 解析器可以处理语法错误,其中一个库可以验证数据结构。

    【讨论】:

    • 投票赞成 Voluptuous,flatland 看起来与 yaml 验证库完全不同。
    【解决方案5】:

    鉴于 JSON 和 YAML 非常相似,您可以使用 JSON-Schema 来验证 YAML 的相当大的子集。这是一个代码 sn-p(您需要安装 PyYAMLjsonschema):

    from jsonschema import validate
    import yaml
    
    schema = """
    type: object
    properties:
      testing:
        type: array
        items:
          enum:
            - this
            - is
            - a
            - test
    """
    
    good_instance = """
    testing: ['this', 'is', 'a', 'test']
    """
    
    validate(yaml.load(good_instance), yaml.load(schema)) # passes
    
    # Now let's try a bad instance...
    
    bad_instance = """
    testing: ['this', 'is', 'a', 'bad', 'test']
    """
    
    validate(yaml.load(bad_instance), yaml.load(schema))
    
    # Fails with:
    # ValidationError: 'bad' is not one of ['this', 'is', 'a', 'test']
    #
    # Failed validating 'enum' in schema['properties']['testing']['items']:
    #     {'enum': ['this', 'is', 'a', 'test']}
    #
    # On instance['testing'][3]:
    #     'bad'
    

    其中一个问题是,如果您的架构跨越多个文件并且您使用"$ref" 来引用其他文件,那么我认为其他文件将需要是 JSON。但可能有办法解决这个问题。在我自己的项目中,我正在使用 JSON 文件指定架构,而实例是 YAML。

    【讨论】:

    • 加一(因为 SE 不喜欢“+1”):jsonschema 与存储格式无关,因此只要它们反序列化为 Python 对象,它就可以处理任何类型的输入和模式.
    • ...但我建议您使用safe_load 而不是load
    • 我建立了一个网站来跟踪tooling support for to using JSON Schema with YAML。目前,Visual Studio Code 中有编辑器支持(通过扩展)和命令行验证工具。
    • 无论如何使用模式有什么意义?我的意思是,如果 yaml 必须是确切的文本,那是没用的。
    • 可以保留json中指定的json schema,防止出现ref问题吗?
    【解决方案6】:

    我也遇到了同样的情况。我需要验证 YAML 的元素。

    首先我认为“PyYAML 标签”是最好和最简单的方法。但后来决定使用“PyKwalify”,它实际上为 YAML 定义了一个模式。

    PyYAML 标签:

    YAML 文件有一个标签支持,我们可以通过为数据类型添加前缀来强制执行这些基本检查。 (例如)对于整数 - !!int "123"

    更多关于 PyYAML:http://pyyaml.org/wiki/PyYAMLDocumentation#Tags 这很好,但是如果您要将其公开给最终用户,则可能会引起混淆。 我做了一些研究来定义 YAML 的模式。这个想法就像我们可以使用其相应的模式来验证 YAML 以进行基本数据类型检查。甚至我们的自定义验证,如 IP 地址、随机字符串也可以添加到其中。所以我们可以让我们的架构分开,让 YAML 简单易读。

    我无法发布更多链接。请 'google schema for YAM'L 查看架构讨论。

    PyKwalify:

    有一个名为 PyKwalify 的包可用于此目的:https://pypi.python.org/pypi/pykwalify

    这个包最符合我的要求。 我在本地设置中尝试了一个小示例,并且正在工作。这是示例架构文件。

    #sample schema
    
    type: map
    mapping:
        Emp:
            type:    map
            mapping:
                name:
                    type:      str
                    required:  yes
                email:
                    type:      str
                age:
                    type:      int
                birth:
                    type:     str
    

    此架构的有效 YAML 文件

    ---
    Emp:
        name:   "abc"
        email:  "xyz@gmail.com"
        age:    yy
        birth:  "xx/xx/xxxx"
    

    谢谢

    【讨论】:

      【解决方案7】:

      您可以使用 python 的 yaml 库来显示已加载文件的消息/字符/行/文件。

      #!/usr/bin/env python
      
      import yaml
      
      with open("example.yaml", 'r') as stream:
          try:
              print(yaml.load(stream))
          except yaml.YAMLError as exc:
              print(exc)
      

      错误信息可以通过exc.problem访问

      访问exc.problem_mark 以获取<yaml.error.Mark> 对象。

      这个对象允许你访问属性

      • 姓名

      因此您可以创建自己的指向问题的指针:

      pm = exc.problem_mark
      print("Your file {} has an issue on line {} at position {}".format(pm.name, pm.line, pm.column))
      

      【讨论】:

      • 这仅验证基本的 YAML 格式 - 而不是任何类型的架构。
      【解决方案8】:

      我发现 Cerberus 非常可靠,文档丰富且易于使用。

      这是一个基本的实现示例:

      my_yaml.yaml:

      name: 'my_name'
      date: 2017-10-01
      metrics:
          percentage:
          value: 87
          trend: stable
      

      schema.py 中定义验证模式:

      {
          'name': {
              'required': True,
              'type': 'string'
          },
          'date': {
              'required': True,
              'type': 'date'
          },
          'metrics': {
              'required': True,
              'type': 'dict',
              'schema': {
                  'percentage': {
                      'required': True,
                      'type': 'dict',
                      'schema': {
                          'value': {
                              'required': True,
                              'type': 'number',
                              'min': 0,
                              'max': 100
                          },
                          'trend': {
                              'type': 'string',
                              'nullable': True,
                              'regex': '^(?i)(down|equal|up)$'
                          }
                      }
                  }
              }
          }
      }
      

      使用PyYaml 加载yaml 文档:

      import yaml
      def load_doc():
          with open('./my_yaml.yaml', 'r') as stream:
              try:
                  return yaml.load(stream)
              except yaml.YAMLError as exception:
                  raise exception
      
      ## Now, validating the yaml file is straightforward:
      from cerberus import Validator
      schema = eval(open('./schema.py', 'r').read())
          v = Validator(schema)
          doc = load_doc()
          print(v.validate(doc, schema))
          print(v.errors)
      

      请记住,Cerberus 是一个不可知论的数据验证工具,这意味着它可以支持 YAML 以外的格式,例如 JSON、XML 等。

      【讨论】:

      • 你应该直接做print(v.validate(doc)),因为你已经用schema对象实例化了Validator类。
      【解决方案9】:

      我包装了一些现有的与 json 相关的 python 库旨在能够将它们与 yaml 一起使用

      生成的python库主要包装...

      • jsonschema - 针对json-schema 文件的json 文件的验证器,被包装以支持针对json-schema 格式的json-schema 文件验证yaml 文件。

      • jsonpath-ng - 用于 python 的 JSONPath 的实现,被包装以支持直接在 yaml 文件上选择 JSONPath

      ...并且在 github 上可用:

      https://github.com/yaccob/ytools

      可以使用pip安装:

      pip install ytools

      验证示例(来自https://github.com/yaccob/ytools#validation):

      import ytools
      ytools.validate("test/sampleschema.yaml", ["test/sampledata.yaml"])
      

      您还没有开箱即用的内容是针对yaml 格式的外部模式进行验证。

      ytools 并没有提供以前不存在的任何东西——它只是让一些现有解决方案的应用更加灵活和方便。

      【讨论】:

        【解决方案10】:

        您可以将 YAML 文档加载为 dict 并使用库 schema 进行检查:

        from schema import Schema, And, Use, Optional, SchemaError
        import yaml
        
        schema = Schema(
                {
                    'created': And(datetime.datetime),
                    'author': And(str),
                    'email': And(str),
                    'description': And(str),
                    Optional('tags'): And(str, lambda s: len(s) >= 0),
                    'setup': And(list),
                    'steps': And(list, lambda steps: all('=>' in s for s in steps), error='Steps should be array of string '
                                                                                          'and contain "=>" to separate'
                                                                                          'actions and expectations'),
                    'teardown': And(list)
                }
            )
        
        with open(filepath) as f:
           data = yaml.load(f)
           try:
               schema.validate(data)
           except SchemaError as e:
               print(e)
        

        【讨论】:

          【解决方案11】:

          Pydantic 未被提及。

          从他们的例子中:

          from datetime import datetime
          from typing import List, Optional
          from pydantic import BaseModel
          
          
          class User(BaseModel):
              id: int
              name = 'John Doe'
              signup_ts: Optional[datetime] = None
              friends: List[int] = []
          
          
          # Parse your YAML into a dictionary, then validate against your model.
          external_data = {
              'id': '123',
              'signup_ts': '2019-06-01 12:22',
              'friends': [1, 2, '3'],
          }
          user = User(**external_data)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-03
            • 2019-06-12
            • 1970-01-01
            • 1970-01-01
            • 2019-01-30
            • 2022-12-18
            • 2010-09-23
            • 2011-01-28
            相关资源
            最近更新 更多