100

One of the benefits of XML is being able to validate a document against an XSD. YAML doesn't have this feature, so how can I validate that the YAML document I open is in the format expected by my application?

1

11 Answers 11

66

Given that JSON and YAML are pretty similar beasts, you could make use of JSON-Schema to validate a sizable subset of YAML. Here's a code snippet (you'll need PyYAML and jsonschema installed):

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'

One problem with this is that if your schema spans multiple files and you use "$ref" to reference the other files then those other files will need to be JSON, I think. But there are probably ways around that. In my own project, I'm playing with specifying the schema using JSON files whilst the instances are YAML.

7
  • 2
    plus one (because SE doesn't like "+1"): jsonschema is storage-format-agnostic so it will work with input and schemas of any type as long as they deserialize to a Python object.
    – Jason S
    Commented Jan 5, 2015 at 18:02
  • 9
    ...but I suggest you use safe_load rather than load.
    – Jason S
    Commented Jan 5, 2015 at 18:03
  • 5
    I built a website to track tooling support for to using JSON Schema with YAML. Currently, there is editor support in Visual Studio Code (via extension) and a command-line validation tool.
    – vossad01
    Commented Jun 30, 2017 at 1:53
  • What's the point of using a schema anyway? I mean if the yaml has to be the exact text, it's kind of useless.
    – Thomas
    Commented Dec 1, 2020 at 17:04
  • 1
    @Thomas an example: a user enters an integer to a config yaml file where instead a float is expected, then the application may start to behave unexpectedly. Just an example.
    – bonobo
    Commented Oct 28, 2022 at 9:19
29

I find Cerberus to be very reliable with great documentation and straightforward to use.

Here is a basic implementation example:

my_yaml.yaml:

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

Defining the validation schema in 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)$'
                    }
                }
            }
        }
    }
}

Using the PyYaml to load a yaml document:

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)

Keep in mind that Cerberus is an agnostic data validation tool, which means that it can support formats other than YAML, such as JSON, XML and so on.

3
  • 1
    You should do print(v.validate(doc)) directly, cause you have already instanciated the Validator class with the schema object.
    – nixmind
    Commented Nov 23, 2021 at 11:06
  • 1
    At the time of writing, the package is no longer actively maintained: github.com/pyeve/cerberus/issues/577#issuecomment-1282216209 Commented Jan 6, 2023 at 13:44
  • The Cerberus project is active again.
    – the_RR
    Commented Aug 3, 2024 at 0:48
20

You can load YAML document as a dict and use library schema to check it:

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)
1
  • 1
    Interesting how this very natural python validator got only 8 upvotes against the clunky JSON-scheme and Cerberus. Probably many people probably instinctively sees json notation as "proper" for a yaml validatior. However, natual data representation usually comes with optional simplifications and that is where Schema shines and json is terse. Commented Jul 17, 2022 at 9:32
16

Pydantic has not been mentioned.

From their example:

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)
14

Try Rx, it has a Python implementation. It works on JSON and YAML.

From the Rx site:

"When adding an API to your web service, you have to choose how to encode the data you send across the line. XML is one common choice for this, but it can grow arcane and cumbersome pretty quickly. Lots of webservice authors want to avoid thinking about XML, and instead choose formats that provide a few simple data types that correspond to common data structures in modern programming languages. In other words, JSON and YAML.

Unfortunately, while these formats make it easy to pass around complex data structures, they lack a system for validation. XML has XML Schemas and RELAX NG, but these are complicated and sometimes confusing standards. They're not very portable to the kind of data structure provided by JSON, and if you wanted to avoid XML as a data encoding, writing more XML to validate the first XML is probably even less appealing.

Rx is meant to provide a system for data validation that matches up with JSON-style data structures and is as easy to work with as JSON itself."

3
  • This looks interesting. It's not clear how well it will handle python objects that are encoded in the yaml, but it's worth a try.
    – Jon
    Commented Jul 16, 2010 at 7:35
  • 4
    Can you share some usage examples? looked in the documentation but could not understand
    – NI6
    Commented Jun 14, 2017 at 10:22
  • 7
    There hasn't been a release of Rx since 2014, and no commits since 2015.
    – Graham Lea
    Commented May 24, 2021 at 13:21
12

Yes - having support for validation is vital for lots of important use cases. See e.g. YAML and the importance of Schema Validation « Stuart Gunter

As already mentioned, there is Rx, available for various languages, and Kwalify for Ruby and Java.

See also the PyYAML discussion: YAMLSchemaDiscussion.

A related effort is JSON Schema, which even had some IETF standardization activity: draft-zyp-json-schema-03 - A JSON Media Type for Describing the Structure and Meaning of JSON Documents

8

I worked on a similar project where I need to validate the elements of YAML.

First, I thought 'PyYAML tags' is the best and simple way. But later decided to go with 'PyKwalify' which actually defines a schema for YAML.

PyYAML tags:

The YAML file has a tag support where we can enforce this basic checks by prefixing the data type. (e.g) For integer - !!int "123"

More on PyYAML: http://pyyaml.org/wiki/PyYAMLDocumentation#Tags This is good, but if you are going to expose this to the end user, then it might cause confusion. I did some research to define a schema of YAML.

  • Validate the YAML with its corresponding schema for basic data type check.
  • Custom validations like IP address, random strings can be added in schema.
  • Have YAML schema separately leaving YAML data simple and readable.

PyKwalify:

There is a package called PyKwalify which serves this purpose: https://pypi.python.org/pypi/pykwalify

This package best fits my requirements. I tried this with a small example in my local set up, and is working. Heres the sample schema file.

#sample schema

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

Valid YAML file for this schema

---
Emp:
    name:   "abc"
    email:  "[email protected]"
    age:    yy
    birth:  "xx/xx/xxxx"
                                                                

Thanks

2
  • PyKwalify seems great. Unfortunately it does not mention supporting Python 3.10 and 3.11 and a version hasn't been released since 2020. Great answer though. Commented May 22, 2023 at 6:43
  • 1
    @tommy.carstensen FWIW whilst there hasn't been much activity, there are 4 commits to the codebase since the last release, one very recently. See github.com/Grokzen/pykwalify/commits/master Commented Dec 5, 2023 at 2:14
4

These look good. The yaml parser can handle the syntax erorrs, and one of these libraries can validate the data structures.

1
  • 2
    The upvote is for Voluptuous, flatland looks like something totally different to a yaml validation library. Commented Jun 17, 2015 at 17:49
1

You can use python's yaml lib to display message/char/line/file of your loaded file.

#!/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)

The error message can be accessed via exc.problem

Access exc.problem_mark to get a <yaml.error.Mark> object.

This object allows you to access attributes

  • name
  • column
  • line

Hence you can create your own pointer to the issue:

pm = exc.problem_mark
print("Your file {} has an issue on line {} at position {}".format(pm.name, pm.line, pm.column))
1
  • 6
    This only validates basic YAML formatting - not any kind of schema.
    – Saustrup
    Commented Sep 12, 2018 at 6:55
1

I wrapped some existing json-related python libraries aiming for being able to use them with yaml as well.

The resulting python library mainly wraps ...

  • jsonschema - a validator for json files against json-schema files, being wrapped to support validating yaml files against json-schema files in yaml-format as well.

  • jsonpath-ng - an implementation of JSONPath for python, being wrapped to support JSONPath selection directly on yaml files.

... and is available on github:

https://github.com/yaccob/ytools

It can be installed using pip:

pip install ytools

Validation example (from https://github.com/yaccob/ytools#validation):

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

What you don't get out of the box yet, is validating against external schemas that are in yaml format as well.

ytools is not providing anything that hasn't existed before - it just makes the application of some existing solutions more flexible and more convenient.

-7

I'm not aware of a python solution. But there is a ruby schema validator for YAML called kwalify. You should be able to access it using subprocess if you don't come across a python library.

1
  • 3
    I'm really looking for a pythonic solution. This is always a last resort.
    – Jon
    Commented Jul 16, 2010 at 7:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.