diff options
Diffstat (limited to '')
-rw-r--r-- | _doc/example.ryd | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/_doc/example.ryd b/_doc/example.ryd new file mode 100644 index 0000000..4b431cd --- /dev/null +++ b/_doc/example.ryd @@ -0,0 +1,255 @@ +version: 0.2 +text: md +pdf: false +--- | +# Examples + +Basic round trip of parsing YAML to Python objects, modifying and +generating YAML: +--- !python | + import sys + from ruamel.yaml import YAML + + inp = """\ + # example + name: + # details + family: Smith # very common + given: Alice # one of the siblings + """ + + yaml = YAML() + code = yaml.load(inp) + code['name']['given'] = 'Bob' + + yaml.dump(code, sys.stdout) + +--- !stdout | +Resulting in:: +--- | +------------------------------------------------------------------------ + +YAML handcrafted anchors and references as well as key merging are +preserved. The merged keys can transparently be accessed using `[]` and +`.get()`: +--- !python | + from ruamel.yaml import YAML + + inp = """\ + - &CENTER {x: 1, y: 2} + - &LEFT {x: 0, y: 2} + - &BIG {r: 10} + - &SMALL {r: 1} + # All the following maps are equal: + # Explicit keys + - x: 1 + y: 2 + r: 10 + label: center/big + # Merge one map + - <<: *CENTER + r: 10 + label: center/big + # Merge multiple maps + - <<: [*CENTER, *BIG] + label: center/big + # Override + - <<: [*BIG, *LEFT, *SMALL] + x: 1 + label: center/big + """ + + yaml = YAML() + data = yaml.load(inp) + assert data[7]['y'] == 2 +--- | +The `CommentedMap`, which is the `dict` like construct one gets when +round-trip loading, supports insertion of a key into a particular +position, while optionally adding a comment: +--- !python | + import sys + from ruamel.yaml import YAML + + yaml_str = """\ + first_name: Art + occupation: Architect # This is an occupation comment + about: Art Vandelay is a fictional character that George invents... + """ + + yaml = YAML() + data = yaml.load(yaml_str) + data.insert(1, 'last name', 'Vandelay', comment="new key") + yaml.dump(data, sys.stdout) + +--- !stdout | +gives:: +--- | +Please note that the comment is aligned with that of its neighbour (if +available). + +The above was inspired by a +[question](http://stackoverflow.com/a/36970608/1307905) posted by +*demux* on StackOverflow. + +------------------------------------------------------------------------ + +By default `ruamel.yaml` indents with two positions in block style, for +both mappings and sequences. For sequences the indent is counted to the +beginning of the scalar, with the dash taking the first position of the +indented \"space\". + +You can change this default indentation by e.g. using `yaml.indent()`: +--- !python | + +import sys +from ruamel.yaml import YAML + +d = dict(a=dict(b=2),c=[3, 4]) +yaml = YAML() +yaml.dump(d, sys.stdout) +print('0123456789') +yaml = YAML() +yaml.indent(mapping=4, sequence=6, offset=3) +yaml.dump(d, sys.stdout) +print('0123456789') + + +--- !stdout | + +giving:: + + +--- | +If a block sequence or block mapping is the element of a sequence, the +are, by default, displayed +[compact](http://yaml.org/spec/1.2/spec.html#id2797686) notation. This +means that the dash of the \"parent\" sequence is on the same line as +the first element resp. first key/value pair of the child collection. + +If you want either or both of these (sequence within sequence, mapping +within sequence) to begin on the next line use `yaml.compact()`: +--- !python | + +import sys +from ruamel.yaml import YAML + +d = [dict(b=2), [3, 4]] +yaml = YAML() +yaml.dump(d, sys.stdout) +print('='*15) +yaml = YAML() +yaml.compact(seq_seq=False, seq_map=False) +yaml.dump(d, sys.stdout) + + +--- !stdout | + +giving:: + + +--- | +------------------------------------------------------------------------ + +The following program uses three dumps on the same data, resulting in a +stream with three documents: +--- !python | +import sys +from ruamel.yaml import YAML + +data = {1: {1: [{1: 1, 2: 2}, {1: 1, 2: 2}], 2: 2}, 2: 42} + +yaml = YAML() +yaml.explicit_start = True +yaml.dump(data, sys.stdout) +yaml.indent(sequence=4, offset=2) +yaml.dump(data, sys.stdout) + + +def sequence_indent_four(s): + # this will fail on direclty nested lists: {1; [[2, 3], 4]} + levels = [] + ret_val = '' + for line in s.splitlines(True): + ls = line.lstrip() + indent = len(line) - len(ls) + if ls.startswith('- '): + if not levels or indent > levels[-1]: + levels.append(indent) + elif levels: + if indent < levels[-1]: + levels = levels[:-1] + # same -> do nothing + else: + if levels: + if indent <= levels[-1]: + while levels and indent <= levels[-1]: + levels = levels[:-1] + ret_val += ' ' * len(levels) + line + return ret_val + +yaml = YAML() +yaml.explicit_start = True +yaml.dump(data, sys.stdout, transform=sequence_indent_four) + +--- !stdout | +gives as output:: + +--- | +The transform example, in the last document, was inspired by a [question +posted by \*nowox\*](https://stackoverflow.com/q/44388701/1307905) on +StackOverflow. + +------------------------------------------------------------------------ + +## Output of `dump()` as a string + +The single most abused "feature" of the old API is not providing the +(second) stream parameter to one of the `dump()` variants, in order to +get a monolithic string representation of the stream back. + +Apart from being memory inefficient and slow, quite often people using +this did not realise that `print(round_trip_dump(dict(a=1, b=2)))` gets +you an extra, empty, line after `b: 2`. + +The real question is why this functionality, which is seldom really +necessary, is available in the old API (and in PyYAML) in the first +place. One explanation you get by looking at what someone would need to +do to make this available if it weren\'t there already. Apart from +subclassing the `Serializer` and providing a new `dump` method, which +would ten or so lines, another **hundred** lines, essentially the whole +`dumper.py` file, would need to be copied and to make use of this +serializer. + +The fact is that one should normally be doing +`round_trip_dump(dict(a=1, b=2)), sys.stdout)` and do away with 90% of +the cases for returning the string, and that all post-processing YAML, +before writing to stream, can be handled by using the `transform=` +parameter of dump, being able to handle most of the rest. But it is also +much easier in the new API to provide that YAML output as a string if +you really need to have it (or think you do): +--- !python | +import sys +from ruamel.yaml import YAML +from ruamel.yaml.compat import StringIO + +class MyYAML(YAML): + def dump(self, data, stream=None, **kw): + inefficient = False + if stream is None: + inefficient = True + stream = StringIO() + YAML.dump(self, data, stream, **kw) + if inefficient: + return stream.getvalue() + +yaml = MyYAML() # or typ='safe'/'unsafe' etc +--- | +with about one tenth of the lines needed for the old interface, you can +once more do: +--- !code | +print(yaml.dump(dict(a=1, b=2))) +--- | +instead of: +--- !code | +yaml.dump((dict(a=1, b=2)), sys.stdout) +print() # or sys.stdout.write('\n') |