How can I get comments from a YAML file using ruamel.yaml in Python?
Asked Answered
S

1

9

I'd like to get the comment strings from a YAML file I loaded using ruamel.yaml. The project documentation lacks an API reference and I can't find a relevant example. What's the right way to access the comments?

import ruamel.yaml

yaml = """\
%YAML 1.2
---
# C1
a: # C2
  # C3
  # C4
  b: 1 # C5
  c: # A comment here will not be parsed properly by ruamel.yaml v0.11.14
  - abc # C6
  - xyz # C7
  # C8
# C9
"""

loaded = ruamel.yaml.round_trip_load(yaml)

# Now what?
Solfeggio answered 7/7, 2016 at 18:12 Comment(2)
It is indeed still not possible to have comment on a line that only has a key and properly preserve that. That is one of the reasons there is no API, as for that ruamel.yaml should be more complete (including supporting these infrequent cases for which the underlying datastructure should change). The comment storage will also need meaningful attribute names instead of list indices (in some scrambled order). ruamel.yaml should get rid of more of PyYAMLs legacy and comment round-tripping should also work when using the C based parser stages.Lowly
And then there is of course the problem of deciding if a comment on a line of its own belongs to the previous scalar, or to the next one etc.Lowly
S
8

The library author comments on this in an issue on BitBucket (May 9, 2016):

The comment preservation has not stabilized, e.g. I need to do something if the key and value of a mapping are not on the same line and the key (or both key and value) have a comment. And my initial target was preservation of existing comments, not so much manipulation.

Through some experimentation I determined the following works for the example code provided in the question above:

print('Comment 1: ' + loaded.ca.comment[1][0].value)
print('Comment 2: ' + loaded.ca.items['a'][2].value)
print('Comment 3: ' + loaded.ca.items['a'][3][0].value)
print('Comment 4: ' + loaded.ca.items['a'][3][1].value)
print('Comment 5: ' + loaded['a'].ca.items['b'][2].value)
print('Comment 6: ' + loaded['a']['c'].ca.items[0][0].value)
print('Comment 7: ' + loaded['a']['c'].ca.items[1][0].value)
print('Comment 8: ' + loaded['a']['c'].ca.end[0].value)
print('Comment 9: ' + loaded['a']['c'].ca.end[1].value)
Solfeggio answered 7/7, 2016 at 18:12 Comment(1)
Yes, in general if you have a mapping/dict object you use ca.items[key] to get the comments associated with the key, and similarly for sequences/list you use ca.items[index]` for a particular element. The manipulation in _test/test_comment_manipulation.py could further give some clues as to how to set new comments.Lowly

© 2022 - 2024 — McMap. All rights reserved.