Dev Ops Ranga
Dev Ops Ranga

Reputation: 213

Python yaml generate few values in quotes

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

Answers (3)

zwer
zwer

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

Anthon
Anthon

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

BoarGules
BoarGules

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

Related Questions