5

I have a Python list, my_list that looks like this ["test1", "test2", "test3"]. I simply want to dump it to a YAML file without quotes. So the desired output is:

test_1
test_2
test_3

I've tried:

import yaml
with open("my_yaml.yaml", "w") as f:
    yaml.safe_dump(my_list, f)

Unfortunately, this includes all 3 elements on a single line and they're quoted:

'test_1', 'test_2', 'test_3'

How can I modify to get the desired output?

Anthon
  • 59,987
  • 25
  • 170
  • 228
anon_swe
  • 8,021
  • 17
  • 78
  • 129

2 Answers2

6

Try using default_style=None to avoid quotes, and default_flow_style=False to output items on separate lines:

yaml.safe_dump(my_list, f, default_style=None, default_flow_style=False)
blhsing
  • 77,832
  • 6
  • 59
  • 90
  • Thanks. So it's now one per line but it has a dash to start each line and still quoted :( – anon_swe Aug 09 '18 at 01:29
  • Your actual data must contain special characters, in which case it would be quoted no matter what. With your example data `test_1`, etc., it would not be quoted. And the dashes before the start of each line is just how YAML formats list data. – blhsing Aug 09 '18 at 01:38
1

You want to output a Python list as a multi-line plain scalar and that is going to be hard. Normally a list is output a YAML sequence, which has either dashes (-, in block style, over multiple lines) or using square brackets ([], in flow style, on one or more lines.

Block style with dashes:

import sys
from ruamel.yaml import YAML

data = ["test1", "test2", "test3"]

yaml = YAML()
yaml.dump(data, sys.stdout)

gives:

- test1
- test2
- test3

flow style, on a narrow line:

yaml = YAML()
yaml.default_flow_style = True
yaml.dump(data, sys.stdout)

output:

Flow style, made narrow:

[test1, test2, test3]
yaml = YAML()
yaml.default_flow_style = True
yaml.width = 5
yaml.dump(data, sys.stdout)

gets you:

[test1,
test2,
test3]

This is unlikely what you want as it affects the whole YAML document, and you still got the square brackets.

One alternative is converting the string to a plain scalar. This is actualy what your desired output would be loaded as.

yaml_str = """\
test_1
test_2
test_3
"""

yaml = YAML()
x = yaml.load(yaml_str)
assert type(x) == str
assert x == 'test_1 test_2 test_3'

Loading your expected output is often a good test to see what you need to provide.

Therefore you would have to convert your list to a multi-word string. Once more the problem is that you can only force the line breaks in any YAML library known to me, by setting the width of the document and there is a minimum width for most which is bigger than 4 (although that can be patched that doesn't solve the problem of that this applies to the whole document).

yaml = YAML()
yaml.width = 5
s = ' '.join(data)
yaml.dump(s, sys.stdout)

result:

test1 test2
test3
...

This leaves what is IMO the best solution if you really don't want dashes: to use a literal block style scalar (string):

from ruamel.yaml.scalarstring import PreservedScalarString

yaml = YAML()
s = PreservedScalarString('\n'.join(data) + '\n')
yaml.dump(s, sys.stdout)

In that scalar style newlines are preserved:

|
test1
test2
test3
Anthon
  • 59,987
  • 25
  • 170
  • 228