使用 ruamel.yaml 删除最后一个字典键时保留以下注释
Preserving following comments when removing last dict key with ruamel.yaml
我正在尝试使用 ruamel.yaml
Python 库从大型 YAML 文件中的嵌套词典中删除一些 keys/value 对,同时保留周围的评论。这是我使用的代码的简化版本:
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)
... 以及我正在尝试编辑的随附文件(目的是删除 'color: blue' 行:
▶ cat items.yml
items:
- name: a
color: blue
texture: smooth
# This is a comment above 'c'
# More comment
- name: b
texture: wrinkled
color: yellow
对于那个特定的文件,代码可以满足我的要求:
▶ ./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
是第一个字典中的 last key/value 对,则第二个项目之前的注释被吃掉:
▶ 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
评论似乎附加到词典的最后 key/value 对,而不是表示为第二项之前的 'leading' 评论。
有没有办法在删除字典中的最后一个键时保留下一项之前的注释?
评论与最后解析的集合节点关联,基于
映射的键或序列的索引。你的评论
"before",实际上是在最后一个之后的行尾注释
第一个序列项的键值对,扩展到多个
行。
如果你使用print(parsed['items'][0].ca)
打印dict like对象(一个CommentedMap
)的注释属性,你会得到:
items={'color': [None, None, CommentToken("\n\n # This is a comment above 'c'\n # More comment\n", line: 5, col: 2), None]})
所以如果你从CommentedMap
中删除键color
,转储parsed
将不再输出
评论,因为没有自动机制将评论与另一个键或某个更高的节点相关联。
您可以 "move" 通过跟踪循环中的前一个键来评论该评论:
parsed['items'][0].ca.items['texture'] = parsed['items'][0].ca.items.pop('color')
这需要您跟踪上一个密钥:
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) 是
可能,但不是那么微不足道
没必要混老API
(ruamel.yaml.round_trip_load()
) 与新的 (yaml=YAML()
)
你应该从 with
语句中获取 for 循环,文件
可以在 round_trip_load(doc)
(或 yaml = ruamel.yaml.YAML(); yaml.load(doc)
)
之后关闭
官方推荐
扩展
YAML 文件的 .yaml
已近 13 年
并确保你有一个测试用例 and/or 固定你正在使用的 ruamel.yaml 版本 (ruamel.yaml<0.17
) 因为这样的评论欺骗不能保证在未来版本。
我正在尝试使用 ruamel.yaml
Python 库从大型 YAML 文件中的嵌套词典中删除一些 keys/value 对,同时保留周围的评论。这是我使用的代码的简化版本:
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)
... 以及我正在尝试编辑的随附文件(目的是删除 'color: blue' 行:
▶ cat items.yml
items:
- name: a
color: blue
texture: smooth
# This is a comment above 'c'
# More comment
- name: b
texture: wrinkled
color: yellow
对于那个特定的文件,代码可以满足我的要求:
▶ ./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
是第一个字典中的 last key/value 对,则第二个项目之前的注释被吃掉:
▶ 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
评论似乎附加到词典的最后 key/value 对,而不是表示为第二项之前的 'leading' 评论。
有没有办法在删除字典中的最后一个键时保留下一项之前的注释?
评论与最后解析的集合节点关联,基于 映射的键或序列的索引。你的评论 "before",实际上是在最后一个之后的行尾注释 第一个序列项的键值对,扩展到多个 行。
如果你使用print(parsed['items'][0].ca)
打印dict like对象(一个CommentedMap
)的注释属性,你会得到:
items={'color': [None, None, CommentToken("\n\n # This is a comment above 'c'\n # More comment\n", line: 5, col: 2), None]})
所以如果你从CommentedMap
中删除键color
,转储parsed
将不再输出
评论,因为没有自动机制将评论与另一个键或某个更高的节点相关联。
您可以 "move" 通过跟踪循环中的前一个键来评论该评论:
parsed['items'][0].ca.items['texture'] = parsed['items'][0].ca.items.pop('color')
这需要您跟踪上一个密钥:
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) 是 可能,但不是那么微不足道
没必要混老API (
ruamel.yaml.round_trip_load()
) 与新的 (yaml=YAML()
)你应该从
with
语句中获取 for 循环,文件 可以在round_trip_load(doc)
(或yaml = ruamel.yaml.YAML(); yaml.load(doc)
) 之后关闭
官方推荐 扩展 YAML 文件的
.yaml
已近 13 年
并确保你有一个测试用例 and/or 固定你正在使用的 ruamel.yaml 版本 (ruamel.yaml<0.17
) 因为这样的评论欺骗不能保证在未来版本。