Reputation: 213
I am using the yaml
module in my Python script to generate a YAML file. The following is an example:
import yaml
class MyDumper(yaml.Dumper):
def increase_indent(self, flow=False, indentless=False):
return super(MyDumper, self).increase_indent(flow, False)
foo = {
'instance_type': 'test',
'hostname': "\"testhost\"",
'name': 'foo',
'my_list': [
{'foo': 'test', 'bar': 'test2'},
{'foo': 'test3', 'bar': 'test4'}],
'hello': 'world',
}
print yaml.dump(foo, Dumper=MyDumper, default_flow_style=False)
Output:
hello: world
hostname: '"testhost"'
instance_type: test
my_list:
- bar: test2
foo: test
- bar: test4
foo: test3
name: foo
In above output hostname value has single and double quotes, I want only double quotes.
Expected output:
hello: world
hostname: "testhost"
instance_type: test
my_list:
- bar: test2
foo: test
- bar: test4
foo: test3
name: foo
Upvotes: 5
Views: 6649
Reputation: 25769
If you insist doing it through PyYAML, you can declare your own forced quotation type and add its representer:
import yaml
class MyDumper(yaml.Dumper): # your force-indent dumper
def increase_indent(self, flow=False, indentless=False):
return super(MyDumper, self).increase_indent(flow, False)
class QuotedString(str): # just subclass the built-in str
pass
def quoted_scalar(dumper, data): # a representer to force quotations on scalars
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
# add the QuotedString custom type with a forced quotation representer to your dumper
MyDumper.add_representer(QuotedString, quoted_scalar)
foo = {
'instance_type': 'test',
'hostname': QuotedString('testhost'), # here's the 'magic'
'name': 'foo',
'my_list': [
{'foo': 'test', 'bar': 'test2'},
{'foo': 'test3', 'bar': 'test4'}],
'hello': 'world',
}
print(yaml.dump(foo, Dumper=MyDumper, default_flow_style=False))
Which will give you:
hello: world hostname: "testhost" instance_type: test my_list: - bar: test2 foo: test - bar: test4 foo: test3 name: foo
Disclaimer: Given the choice, I also prefer Anthon's ruamel.yaml
module for my YAML needs.
Upvotes: 6
Reputation: 76578
You cannot force quotes in YAML by quoting parts of your data as you do. As the quotes force the dumper to apply quoting to the scalar (i.e. can no longer use plain scalars as for the other string values in your yaml file).
You need to make a type that is dumped with quotes. Most easily that
is done using ruamel.yaml
(disclaimer: I am the author of that
enhanced version of PyYAML, supporting YAML 1.2, support round-trip
preservation of comments and quotes etc).
import sys
import ruamel.yaml
from ruamel.yaml.scalarstring import DoubleQuotedScalarString as dq
yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)
foo = {
'instance_type': 'test',
'hostname': dq("testhost"),
'name': 'foo',
'my_list': [
{'foo': 'test', 'bar': 'test2'},
{'foo': 'test3', 'bar': 'test4'}],
'hello': 'world',
}
yaml.dump(foo, sys.stdout)
which gives:
instance_type: test
hostname: "testhost"
name: foo
my_list:
- foo: test
bar: test2
- foo: test3
bar: test4
hello: world
You can also easily load that output and dump it generating exactly same ouput:
from ruamel.yaml.compat import StringIO
buf = StringIO()
yaml.dump(foo, buf)
yaml.preserve_quotes = True
data = yaml.load(buf.getvalue())
yaml.dump(data, sys.stdout)
Upvotes: 4
Reputation: 16942
You are getting doubled quotes because that is what your input data has. This line:
'hostname': "\"testhost\"",
says you want hosthame
to have as a value a 10-character string beginning and ending with "
, and so that is what you are seeing in yaml. This string with escaped double quotes "\"testhost\""
and the yaml version '"testhost"'
are two different source code representations of the same data. You only need doubled quotes around a string in yaml if you want to embed special characters (like \n
for newline) in it. But yaml.dump()
will take care of that for you.
Upvotes: 0