Preserve Empty Message In Ruamel.yaml Roundtrip Parsing
Using ruamel.yaml, the output of roundtrip parsing of the YAML a: {b: } is a: {b: !!null ''} Is there any way to preserve the empty message, or overwrite the None representer t
Solution 1:
This is not trivial and I am not sure if the solution presented below doesn't have adverse side-effects.
The cause for the non-triviality has to do with multiple things:
You are using the less readable flow style
a: {b: }
instead of block style:
a:b:
The latter round-trips without a change
- The empty value for key
b
loads asNone
, which I have not been able to subclass in ruamel.yaml, and hence style information cannot be attached to that value, and you have to rely on the "default" emitter (which in your case doesn't do what you want). This
a: {b:}
is entirely different from your
a: {b: }
and currently the emitter goes for safe and inserts tag information into the stream.
With that background information, you can force the style of the representation for None
to the empty string and based on that hack the emitter:
import sys
import ruamel.yaml
yaml_str = """\
a: {b: }
"""classMyEmitter(ruamel.yaml.emitter.Emitter):
defchoose_scalar_style(self):
# override selection for 'null'if self.analysis isNone:
self.analysis = self.analyze_scalar(self.event.value)
if self.event.style == '"'or self.canonical:
return'"'if (not self.event.style or self.event.style == '?') and \
(self.event.implicit[0] ornot self.event.implicit[2]):
if (not (self.simple_key_context and
(self.analysis.empty or self.analysis.multiline)) and
(self.flow_level and self.analysis.allow_flow_plain or
(not self.flow_level and self.analysis.allow_block_plain))):
return''if (self.event.style == '') and self.event.tag == 'tag:yaml.org,2002:null'and \
(self.event.implicit[0] ornot self.event.implicit[2]):
if self.flow_level andnot self.analysis.allow_flow_plain:
return''
self.analysis.allow_block = Trueif self.event.style and self.event.style in'|>':
if (not self.flow_level andnot self.simple_key_context and
self.analysis.allow_block):
return self.event.style
ifnot self.event.style and self.analysis.allow_double_quoted:
if"'"in self.event.value or'\n'in self.event.value:
return'"'ifnot self.event.style or self.event.style == '\'':
if (self.analysis.allow_single_quoted andnot (self.simple_key_context and self.analysis.multiline)):
return'\''return'"'defprocess_scalar(self):
# if style '' and tag is 'null' insert empty spaceif self.analysis isNone:
self.analysis = self.analyze_scalar(self.event.value)
if self.style isNone:
self.style = self.choose_scalar_style()
split = (not self.simple_key_context)
if self.sequence_context andnot self.flow_level:
self.write_indent()
if self.style == '"':
self.write_double_quoted(self.analysis.scalar, split)
elif self.style == '\'':
self.write_single_quoted(self.analysis.scalar, split)
elif self.style == '>':
self.write_folded(self.analysis.scalar)
elif self.style == '|':
self.write_literal(self.analysis.scalar)
elif self.event.tag == 'tag:yaml.org,2002:null':
self.stream.write(u' ') # not sure if this doesn't break other thingselse:
self.write_plain(self.analysis.scalar, split)
self.analysis = None
self.style = Noneif self.event.comment:
self.write_post_comment(self.event)
classMyRepresenter(ruamel.yaml.representer.RoundTripRepresenter):
defrepresent_none(self, data):
iflen(self.represented_objects) == 0andnot self.serializer.use_explicit_start:
# this will be open ended (although it is not yet)return self.represent_scalar(u'tag:yaml.org,2002:null', u'null')
return self.represent_scalar(u'tag:yaml.org,2002:null', u'', style='')
MyRepresenter.add_representer(type(None),
MyRepresenter.represent_none)
yaml = ruamel.yaml.YAML()
yaml.Emitter = MyEmitter
yaml.Representer = MyRepresenter
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)
which gives:
a: {b: }
Post a Comment for "Preserve Empty Message In Ruamel.yaml Roundtrip Parsing"