I know there are a few questions about this on SO, but I couldn\'t find what I was looking for.
I\'m using pyyaml to read (.load()
) a .yml
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
Below, ruamel.yaml is used instead.
ruamel.yaml
is actively maintained. Unlike PyYAML, ruamel.yaml
supports:
yaml.dump()
to dump a dictionary loaded by a prior call to yaml.load()
:
ruamel.yaml
cleverly respects all input formatting. Everything. The whole stylistic enchilada. The entire literary shebang. All.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.
For backward compatibility with PyYaml, the yaml.load()
and yaml.dump()
functions do not perform roundtrip preservation by default. To do so, explicitly pass:
Loader=ruamel.yaml.RoundTripLoader
keyword parameter to yaml.load()
.Dumper=ruamel.yaml.RoundTripDumper
keyword parameter to yaml.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.
First
To represent dictionary data is used following code:
mapping = list(mapping.items())
try:
mapping = sorted(mapping)
except TypeError:
pass
It is why ordering is changed
Second
Information about how scalar type was presented (with double quote or not) is lost when reading (this is principal approach of library)
Summary
You can create own class based on 'Dumper' and to overload method 'represent_mapping' for changing behaviour how dictionary will be presented
For saving information about double quotes for scalar you must also create own class based on 'Loader', but i am afraid that it will affect and other classes and will doing it difficult