简体   繁体   English

使用 ruamel.yaml 删除最后一个 dict 键时保留以下注释

[英]Preserving following comments when removing last dict key with ruamel.yaml

I'm trying to use the ruamel.yaml Python library to remove some keys/value pairs from nested dictionaries within a large YAML file, while retaining surrounding comments.我正在尝试使用ruamel.yaml Python 库从大型 YAML 文件中的嵌套字典中删除一些键/值对,同时保留周围的注释。 Here's a simplified version of the code I'm using:这是我正在使用的代码的简化版本:

import sys
import ruamel.yaml

with open(sys.argv[1], 'r') as doc:
    parsed = ruamel.yaml.round_trip_load(doc, preserve_quotes=True)

    for item in parsed['items']:
        if item['color'] == 'blue':
            del item['color']

    yaml = ruamel.yaml.YAML(typ='rt')
    yaml.indent(sequence=4, offset=2)
    yaml.dump(parsed, sys.stdout)

... and an accompanying file that I'm trying to edit (the intent is to remove the 'color: blue' line: ...以及我正在尝试编辑的随附文件(目的是删除“颜色:蓝色”行:

▶ cat items.yml
items:
  - name: a
    color: blue
    texture: smooth

  # This is a comment above 'c'
  # More comment
  - name: b
    texture: wrinkled
    color: yellow

With that specific file, the code does what I want:使用该特定文件,代码执行我想要的操作:

▶ ./munge.py items.yml
items:
  - name: a
    texture: smooth

  # This is a comment above 'c'
  # More comment
  - name: b
    texture: wrinkled
    color: yellow

However, if color: blue is the last key/value pair in the first dict, the comment preceding the second item gets eaten:但是,如果color: blue是第一个 dict 中的最后一个键/值对,则第二项之前的注释会被吃掉:

▶ cat items.yml
items:
  - name: a
    texture: smooth
    color: blue

  # This is a comment above 'c'
  # More comment
  - name: b
    texture: wrinkled
    color: yellow
▶ ./munge.py items.yml
items:
  - name: a
    texture: smooth
  - name: b
    texture: wrinkled
    color: yellow

It looks like the comment is being attached to the last key/value pair of the dictionary, rather than being represented as a 'leading' comment preceding the second item.看起来注释被附加到字典的最后一个键/值对,而不是被表示为第二项之前的“前导”注释。

Is there any way to preserve the comment that precedes the next item even when removing the last key in the dict?即使删除字典中的最后一个键,有没有办法保留下一项之前的注释?

Comments are associated with the last collection node parsed, based on the key of a mapping or the the index of a sequence.基于映射的键或序列的索引,注释与解析的最后一个集合节点相关联。 Your comments "before", are actually end-of-line comments following the last key-value pair of the first sequence item, extending over multiple lines.您“之前”的注释实际上是第一个序列项的最后一个键值对之后的行尾注释,扩展到多行。

If you print the comment attribute of the dict like object (a CommentedMap ), using print(parsed['items'][0].ca) , you'll get:如果您使用print(parsed['items'][0].ca) dict 类对象(一个CommentedMap )的 comment 属性,您将获得:

items={'color': [None, None, CommentToken("\n\n  # This is a comment above 'c'\n  # More comment\n", line: 5, col: 2), None]})

So if you delete the key color from the CommentedMap , dumping parsed will no longer output the comment, as there is no automatic mechanism to associate the comment with another key or some higher up node.因此,如果您从CommentedMap删除键color ,转储parsed将不再输出注释,因为没有自动机制将注释与另一个键或某个更高的节点相关联。

You can "move" that comment by keeping track of the previous key in your loop:您可以通过跟踪循环中的上一个键来“移动”该评论:

parsed['items'][0].ca.items['texture'] = parsed['items'][0].ca.items.pop('color')

and that requires you to keep track of the previous key:这需要您跟踪上一个键:

import sys
import ruamel.yaml

yaml_str = """\
items:
  - name: a
    texture: smooth
    color: blue

  # This is a comment associated with the last key of the preceding mapping
  # More of the same comment
  - name: b
    texture: wrinkled
    color: yellow
"""

yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)
yaml.preserve_quotes = True
parsed = yaml.load(yaml_str)
prev = None
for item in parsed['items']:
    for key in item:
        if key == 'color' and item[key] == 'blue':
            if prev is not None:
                item.ca.items[prev] = item.ca.items.pop(key)
            del item['color']
            break
        prev = key
yaml.dump(parsed, sys.stdout)

which gives:这使:

items:
  - name: a
    texture: smooth

  # This is a comment associated with the last key of the preceding mapping
  # More of the same comment
  - name: b
    texture: wrinkled
    color: yellow

A few notes:一些注意事项:

  • moving the comment to the parent (sequence/list/CommentedSeq) is possible, but not as trivial将评论移到父级(序列/列表/CommentedSeq)是可能的,但不是那么简单

  • there is no need to mix the old API ( ruamel.yaml.round_trip_load() ) with the new ( yaml=YAML() )无需将旧 API ( ruamel.yaml.round_trip_load() ) 与新 API ( yaml=YAML() ) 混合

  • you should get the for loop out of the with statement, the file can be closed after round_trip_load(doc) (or yaml = ruamel.yaml.YAML(); yaml.load(doc) )您应该从with语句中获取 for 循环,该文件可以在round_trip_load(doc) (或yaml = ruamel.yaml.YAML(); yaml.load(doc) )之后关闭

  • the officially recommended extension for YAML files has been .yaml for close to 13 years近 13 年来, 官方推荐的 YAML 文件扩展名为.yaml

And make sure you have a test case and/or pin the ruamel.yaml version you are using ( ruamel.yaml<0.17 ) as such comment trickery is not guaranteed to keep working the same way in future versions.并确保你有一个测试用例和/或固定你正在使用的 ruamel.yaml 版本( ruamel.yaml<0.17 ),因为这样的评论ruamel.yaml<0.17不能保证在未来的版本中以相同的方式工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM