Home > Software design >  How can I insert linebreak in YAML with ruamel.yaml?
How can I insert linebreak in YAML with ruamel.yaml?

Time:09-29

Here is the code I have

from ruamel.yaml import YAML

yaml = YAML()
user = [{"login":"login1","fullName":"First1 Last1", "list":["a"]},{"login":"login2","fullName":"First2 Last2", "list":["b"]}]
test = {"category":[{"year":2023,"users":user}]}
yaml.indent(mapping=4, sequence=4, offset=2)
yaml.width = 2048


with open(r'test.yml', 'w') as file:
    documents = yaml.dump(test, file)

And I get this YAML file

category:
  - year: 2023
    users:
      - login: login1
        fullName: First1 Last1
        list:
          - a
      - login: login2
        fullName: First2 Last2
        list:
          - b

I need to insert a linebreak between the two users (the final YAML should look like that)

category:
  - year: 2023
    users:
      - login: login1
        fullName: First1 Last1
        list:
          - a

      - login: login2
        fullName: First2 Last2
        list:
          - b

How can I add this empty line?

CodePudding user response:

You should load the result that you want in ruamel.yaml. For good measure you can then dump it back to see if the extra line is preserved. If it isn't you might not be able to write out such a format in the first place. As you will see the extra line is preserved, so you should be able to get it inothe output in some way if you can reconstruct the loaded data from scratch.

ruamel.yaml normally attaches comments to the node just parsed, so you should investigate the sequence that is the value for the first key 'list':

import sys
import ruamel.yaml

yaml_str = """\
category:
  - year: 2023
    users:
      - login: login1
        fullName: First1 Last1
        list:
          - a

      - login: login2
        fullName: First2 Last2
        list:
          - b
"""

yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
# yaml.preserve_quotes = True
data = yaml.load(yaml_str)
# yaml.dump(data, sys.stdout)
seq = data['category'][0]['users'][0]['list']
print('seq', type(seq), seq.ca)

which gives:

seq <class 'ruamel.yaml.comments.CommentedSeq'> Comment(comment=None,
  items={0: [CommentToken('\n\n', line: 6, col: 12), None, None, None]})

In that seq.ca is the comment attribute. Such an attribute cannot be added to a normal list, so at least for that part of your data structure user you need to create a CommentedSeq instance. You can also see that the comment token consists of two newlines (\n\n). The first newline indicates that the end-of-line comment following 'a' the first element (indicated by 0) is empty, the second newline is your actual empty line before the second "user".

However it is actually easier to insert the line before the second user. The CommentedSeq instance has a method that allows you to add a comment before a key (in this case the key is the element index):

import sys
import ruamel.yaml
CS = ruamel.yaml.comments.CommentedSeq

yaml = ruamel.yaml.YAML()

user = CS([{"login":"login1","fullName":"First1 Last1", "list":["a"]},{"login":"login2","fullName":"First2 Last2", "list":["b"]}])
user.yaml_set_comment_before_after_key(1, before='\n')
test = {"category":[{"year":2023,"users":user}]}
yaml.indent(mapping=4, sequence=4, offset=2)
yaml.width = 2048


documents = yaml.dump(test, sys.stdout)

which gives:

category:
  - year: 2023
    users:
      - login: login1
        fullName: First1 Last1
        list:
          - a

      - login: login2
        fullName: First2 Last2
        list:
          - b

Make sure you fix the version of ruamel.yaml you are using in your installation, routines like yaml_set_comment_before_after_key may still change.

During testing I usually write to stdout, easier to see if the output is correct. If you write the YAML document to a file, you should consider using the extension .yaml, which has been the recommended extension for such files since at least 15 years.

  • Related