PyYAML dump format
Below, ruamel.yaml
is used instead.
ruamel.yaml
is actively maintained. Unlike PyYAML, ruamel.yaml
supports:
- YAML <= 1.2. PyYAML only supports YAML <= 1.1. This is vital, as YAML 1.2 intentionally breaks backward compatibility with YAML 1.1 in several edge cases. This would usually be a bad thing. In this case, this renders YAML 1.2 a strict superset of JSON. Since YAML 1.1 is not a strict superset of JSON, this is a good thing.
-
Roundtrip preservation. When calling
yaml.dump()
to dump a dictionary loaded by a prior call toyaml.load()
:- PyYAML naively ignores all input formatting – including comments, ordering, quoting, and whitespace. Discarded like so much digital refuse into the nearest available bit bucket.
-
ruamel.yaml
cleverly respects all input formatting. Everything. The whole stylistic enchilada. The entire literary shebang. All.
Library Migration
Switching from PyYAML to ruamel.yaml
in existing applications is typically as simple as changing the library import to:
from ruamel import yaml
This works because ruamel.yaml
is a PyYAML fork that conforms to the PyYAML API.
No other changes should be needed. The yaml.load()
and yaml.dump()
functions should continue to behave as expected.
Roundtrip Preservation and What It Can Do for You
For backward compatibility with PyYaml, the yaml.load()
and yaml.dump()
functions do not perform roundtrip preservation by default. To do so, explicitly pass:
- The optional
Loader=ruamel.yaml.RoundTripLoader
keyword parameter toyaml.load()
. - The optional
Dumper=ruamel.yaml.RoundTripDumper
keyword parameter toyaml.dump()
.
An example kindly "borrowed" from ruamel.yaml
documentation:
import ruamel.yaml
inp = """\
# example
name:
# Yet another Great Duke of Hell. He's not so bad, really.
family: TheMighty
given: Ashtaroth
"""
code = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)
code['name']['given'] = 'Astarte' # Oh no you didn't.
print(ruamel.yaml.dump(code, Dumper=ruamel.yaml.RoundTripDumper), end='')
It is done. Comments, ordering, quoting, and whitespace will now be preserved intact.
In my case, I want "
if value contains a {
or a }
, otherwise nothing. For example:
en:
key1: value is 1
key2: 'value is {1}'
To perform that, copy function represent_str()
from file representer.py in module PyYaml and use another style if string contains {
or a }
:
def represent_str(self, data):
tag = None
style = None
# Add these two lines:
if '{' in data or '}' in data:
style = '"'
try:
data = unicode(data, 'ascii')
tag = u'tag:yaml.org,2002:str'
except UnicodeDecodeError:
try:
data = unicode(data, 'utf-8')
tag = u'tag:yaml.org,2002:str'
except UnicodeDecodeError:
data = data.encode('base64')
tag = u'tag:yaml.org,2002:binary'
style = '|'
return self.represent_scalar(tag, data, style=style)
To use it in your code:
import yaml
def represent_str(self, data):
...
yaml.add_representer(str, represent_str)
In this case, no diffences between keys and values and that's enough for me. If you want a different style for keys and values, perform the same thing with function represent_mapping