Reputation: 343
Before I go in, yes I've looked into it already and know that YAML doesn't differentiate quotes and non-quotes and just takes the types as they are. Frankly I think it's nicer without the quotes, but unfortunately that's not what I need. So please try and understand that I have looked into the matter but still do need the quotes around my string objects.
In my code I have a dictionary:
data = {dic:[{A:''}, {B:''}, {C:''}, {D:''},...]}
the 'var*'
are constructed through the PyQt4 QLineEdit
class which the line of code extract the line looks like this:
var* = str(QtGui.QLineEdit().displayText())
So when I do data['dic'][index]['A'-'Z'] = var*
it becomes data = {dic:[{A: 'var1'}, {B:'var2'}, {C:'var3'}, {D:'var4'},...]}
then I dump all my data:
prettyData = yaml.dump(data, default_flow_style=False, width=10000000)
and print prettyData
I get this:
dic:
- A: var1
- B: var2
- C: var3
- D: var4
...
I've tried many things to make them appear:
dic:
- A: 'var1'
- B: 'var2'
- C: 'var3'
- D: 'var4'
...
but haven't been successful yet. I've heard different opinions on the matter ranging from "not possible" to "just put quotes around them", which as you can see, in my case, I cannot do.
Any ideas on how to go about this?
Upvotes: 4
Views: 7663
Reputation: 21
#!/usr/bin/env python2
# quoting_example.py
import yaml
import yaml.representer
def literal_presenter(dumper, data):
if isinstance(data, str) and "\n" in data:
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
yaml.add_representer(str, literal_presenter)
print yaml.dump({"key": "value", "multiline": "foo\nbar"}, default_flow_style=False)
And the result is:
$ python2 quoting_example.py
"key": "value"
"multiline": |-
foo
bar
Similarly, you can add representers for unicode, dicts (think sorted dicts), etc.
Upvotes: 2
Reputation: 76862
You can override the emitter for scalars and change the style of the values emitted on the fly. Depending on the rest of scalar values that you have, you might need to do some more tests to unset is_string
. By the time process_scalar
is called you don't know the original value any more, you just have an event with a (unicode) string value.
import sys
import ruamel.yaml as yaml
yaml_str = """\
dic:
- A: var1 # need to get these strings quoted
- B: var2
- C: var3
- D: var4
- E: 3 # leave this alone
"""
# the scalar emitter from emitter.py
def process_scalar(self):
if self.analysis is None:
self.analysis = self.analyze_scalar(self.event.value)
if self.style is None:
self.style = self.choose_scalar_style()
split = (not self.simple_key_context)
# VVVVVVVVVVVVVVVVVVVV added
if split: # not a key
is_string = True
if self.event.value and self.event.value[0].isdigit():
is_string = False
# insert extra tests for scalars that should not be ?
if is_string:
self.style = "'"
# ^^^^^^^^^^^^^^^^^^^^
# if self.analysis.multiline and split \
# and (not self.style or self.style in '\'\"'):
# 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)
else:
self.write_plain(self.analysis.scalar, split)
self.analysis = None
self.style = None
if self.event.comment:
self.write_post_comment(self.event)
data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)
dd = yaml.RoundTripDumper
dd.process_scalar = process_scalar
yaml.dump(data, sys.stdout, Dumper=dd)
and get as output¹:
dic:
- A: 'var1' # need to get these strings quoted
- B: 'var2'
- C: 'var3'
- D: 'var4'
- E: 3 # leave this alone
¹ This was done using ruamel.yaml of which I am the author. That package is an enhancement of PyYAML. You might be able to do something similar with the latter, but it would drop the comments that are in the input.
Upvotes: 2