使用 ruamel.yaml 删除最后一个 dict 键时保留以下注释 [英] Preserving following comments when removing last dict key with ruamel.yaml

查看:88
本文介绍了使用 ruamel.yaml 删除最后一个 dict 键时保留以下注释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 ruamel.yaml Python 库从大型 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. 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

但是,如果 color: blue 是第一个 dict 中的最后键/值对,则第二项之前的注释会被吃掉:

However, if color: blue is the last key/value pair in the first dict, the comment preceding the second item gets eaten:

▶ 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?

推荐答案

评论与最后解析的集合节点相关联,基于映射的键或序列的索引.你的评论before",实际上是最后一个后的行尾注释第一个序列项的键值对,扩展到多个线.

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.

如果你使用print(parsed['items'][0].ca)打印dict类对象(一个CommentedMap)的comment属性,你会得到:

If you print the comment attribute of the dict like object (a CommentedMap), using print(parsed['items'][0].ca), you'll get:

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

所以如果你从 CommentedMap 中删除键 color,dumping parsed 将不再输出评论,因为没有自动机制将评论与另一个键或某个更高的节点相关联.

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.

您可以通过跟踪循环中的上一个键来移动"该评论:

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)

给出:

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

一些注意事项:

  • 将评论移到父级(sequence/list/CommentedSeq)是可能,但不是那么简单

  • moving the comment to the parent (sequence/list/CommentedSeq) is possible, but not as trivial

不需要混合旧的API(ruamel.yaml.round_trip_load()) 和新的 (yaml=YAML())

there is no need to mix the old API (ruamel.yaml.round_trip_load()) with the new (yaml=YAML())

你应该从 with 语句中取出 for 循环,文件可以在 round_trip_load(doc) 之后关闭(或 yaml = ruamel.yaml.YAML(); yaml.load(doc) )

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) )

官方推荐扩展用于 YAML 文件的 .yaml 已近 13 年

the officially recommended extension for YAML files has been .yaml for close to 13 years

并确保您有一个测试用例和/或固定您正在使用的 ruamel.yaml 版本 (ruamel.yaml<0.17) 因为这样的评论技巧不能保证以同样的方式工作在未来的版本中.

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 删除最后一个 dict 键时保留以下注释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆