This is a collection of tests for YAML, including round-tripping, dumping and loading.
Each of these tests consists of a single file containing one or more YAML documents, so there is no need to combine input and output based on different file extensions to review or edit a test. A file may start with an metadata document, which should be an untagged mapping. All other docs are tagged (often consisting of a literal style scalar). If the metadata is provided then a type of test can be specified within it. If the type of test is not provided (or if there is no metadata document), the type of test is deducted from the tags of the scalar(s) loaded from the document(s) in the file.
E.g. the following test has no metadata and only one document consisting of a tagged scalar:
--- !YAML | number: 42
Since there is only a document with tag !YAML, it is assumed this must round-trip without changes. You can also explicitly provide this round-trip type in a multi-document YAML file, starting with metadata:
issue: 42 type: rt --- !YAML | number: 42
It is optional to provide a type when a test includes metadata. In case you don't include it, it will be deducted in the normal way based on the tag(s) of the other document(s) in the file.
Please note that in the above test, the document starting with the line --- !YAML |, specifies a non-indented root-level, literal style scalar. Such a literal scalar does not have to be indented in YAML. An example for this is provided by the %!PS-Adobe-2.0 scalar in example 9.5 of the YAML standard:
%YAML 1.2 --- | %!PS-Adobe-2.0 ... %YAML1.2 --- # Empty ...
Since trailing whitespace on lines literal scalars is often difficult to see, no space or TAB is allowed to occur before newlines. During loading of a test this is checked.
If your document really needs such a space, you can include it with as a replaced character sequence
The metadata document has to be the first document in the stream and has to be a mapping. As providing the metadata is optional, so is any of the keys, but some processed key might expect some other key to be provided (if so this is indicated in the description)
Of the keys in the mapping the following are processed:
explicitly set YAML version of the input (defaults to 1.2 if not set):
yaml_version: [1, 1]
use this if you do not want to provide a %YAML 1.1 directive in the data.
Examples of other keys (that are not processed):
The rt, or round-trip type is automatically selected if not type is set in the metadata and only a !YAML document or a !YAML and an !Output document are provided.
The round-trip type expects a input !YAML document and optionally an output !Output document. If the output is provided the dump of the loaded input should match the output. If the output is not provided the output should match the input.
Example:
--- !YAML | number: 42 --- !Output | number: 42
The load-assert type is automatically selected if no type is set in the metadata and both a !YAML and an !Assert tagged document are provided. The YAML document is loaded into a data structure named d.
The assert document is either a (literal style) scalar, each of which lines is then asserted on the data. Or it is a mapping with a range and lines keys. The value for range should provide input for the range() function (an integer) assigned to the variable idx, and the lines should again be a (literal style) scalar.
The following:
--- !YAML | - 42 - 49 --- !Assert | 40 < d[0] < 50 40 < d[1] < 50
is equivalent to:
--- !YAML | - 42 - 47 --- !Assert range: 2 lines: | 40 < d[idx] < 50
You don't need to use a literal-style scalar for the test, e.g. you can use a double quoted scalar. You can, if it makes sense, provide multiple asserts in lines when using a range.
The Python-run type is automatically selected if there is a !Python tagged document. This is assumed to contain Python code, which is stored in a file in a temporary directory and executed (and yes, that can be a security risk if anyone can write to your directory with test files).
The output is either compared with a !Output tagged document, if provided, or with a !YAML tagged document. Neither of these is processed, only loaded, so which tag to use, should be determined by the expected output of the program, but is not binding in any way.
Example:
issue: 214
comment: test provided by Douglas RAILLARD
--- !Python |
import sys
from ruamel.yaml import YAML
from ruamel.yaml.compat import StringIO
class UseReduce:
def __init__(self, val):
self.val = val
@classmethod
def restore(cls, val):
return cls(val)
def __reduce__(self):
# Give the callable to call, and a tuple of parameters to restore the object
return (self.restore, (self.val,))
data = UseReduce(42)
yaml = YAML(typ='unsafe')
buf = StringIO()
yaml.dump(data, buf)
res = buf.getvalue()
sys.stdout.write(res)
--- !YAML |
!!python/object/apply:__main__.UseReduce.restore [42]
If all three of !YAML, !Python and !Output are provided (and they should be in that order), then the YAML stream is available in the file input.yaml and processing it using the Python code is expected to generate the output:
--- !YAML |
a: 1
b: 2
--- !Python |
import sys
from pathlib import Path
from ruamel.yaml import YAML
yaml = YAML()
data = yaml.load(Path('input.yaml'))
del data['a']
data.insert(0, 'c', 3)
yaml.dump(data, sys.stdout)
--- !Output |
c: 3
b: 2
Sometimes you need a space in the input, where it is difficult to see (or not allowed at the end of the line), or a directive end marker (---) in a non-indented literal-style document
On loading literal style scalar documents, the following sequences are replaced:
The replacement is done after checking for space/tab occuring before end-of-line.