How can I insert linebreak in YAML with ruamel.yaml?
Asked Answered
C

1

6

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?

Consensual answered 29/9, 2021 at 13:2 Comment(4)
not sure there is a "proper" way to do it other than post-processing your output file and adding the lines. The real question is why would you need the extra lines there in the first place? maybe there is a better solution?Spumescent
I need to generate a file which is coherent with a previous file already existing, that's why I can't just not have this empty lineConsensual
Since ruamel.yaml can roundtrip the YAML document preserving the empty line, there is no need for post-processing, you just have to find out where to attach the comment (an empty line is considered a comment that doesn't start with a #)Package
@AlexandreBarbier Try to use question sentences, for which the answer actually helps you. On your original "would someone be able to help" the only appropriate answer I could give is "yes". Welcome to Stack OverflowPackage
P
3

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.

Package answered 29/9, 2021 at 14:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.