RUAMEL/PYYAML writting new lines to yaml

36 views Asked by At

I have a large yaml configuration file I am editing. This is the ideal format.

...
- name: apple
  Formula: |-
    x = 3 + 4;
    apple = x * 3 + y;
  Inputs:
  - y
- name: banana
  Formula: |-
    x = 8 + 4;
    apple = x * 3 + y;
  Inputs:
  - y
...

Using a github action and issue template I am automating the addition of new items. Lets say the user wants to add apple above using the github issue template. A python script outputs this (below) and its not in my ideal format. My question is how to fix this.

- name: apple
  Formula: "x = 3 + 4;\n\rapple = x * 3 + y;"
  Inputs:
  - y

I have a template yaml file that gets loaded and edited. A print statement on the string outputs newlines as newlines. So its not a raw string. The relevant python code:

import json
from ruamel.yaml import YAML

template[0]["Formula"] = newparam["Formula"] # newparam is the dict from the jsonload
targetyaml.append(template[0])

yaml = YAML()
yaml.default_flow_style = False
with open(afile, "w") as outfile:
    yaml.dump(targetyaml, outfile)

Note: the round trip of the list items that already have good formatting is maintained. Its only this added parameter that is not formatting the way I want.

I tried string replacing the newline characters in a few ways to get the dump to interpret the newlines literally.

1

There are 1 answers

0
Anthon On

If you are stuck with generating YAML the way you want it, there are two things to do:

  • round-trip the expected output, and see if ruamel.yaml can preserve the form
  • if it can preserve the form, inspect the data structure and try to generate it from scratch

Start with round-tripping:

import sys
import ruamel.yaml

yaml_str = """\
- name: apple
  Formula: |-
    x = 3 + 4;
    apple = x * 3 + y;
  Inputs:
  - y
"""
    
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

which gives:

- name: apple
  Formula: |-
    x = 3 + 4;
    apple = x * 3 + y;
  Inputs:
  - y

So the chomped literal scalar is preserved (you already knew that from the other parts of the document). Now inspect how that scalar is loaded:

lit = data[0]['Formula']
print('inspecting:', repr(lit), 'type:', type(lit))

which prints:

inspecting: 'x = 3 + 4;\napple = x * 3 + y;' type: <class 'ruamel.yaml.scalarstring.LiteralScalarString'>

Using that type:

from ruamel.yaml.scalarstring import LiteralScalarString as LSS

data = [dict(name='apple', Formula=LSS('x = 8 + 4\naple = x * 3 + y;'), Inputs=['y'])]
yaml.dump(data, sys.stdout)

which gives:

- name: apple
  Formula: |-
    x = 8 + 4
    aple = x * 3 + y;
  Inputs:
  - y

Whether or not (and which) comping indicator you get is determined how many newlines end the string that you pass to LSS/LiteralScalarString. If there is no newline you get the stripping chomping indicator (-).