在保留注释的同时向 yaml 添加/添加新条目
prepending / adding new entries to yaml while preserving comment
我想将条目添加到带有注释的现有 yaml 文件的开头(或结尾,这无关紧要),我希望保留这些注释。有没有一种优雅的方法可以使用 ruamel.yaml
?
import sys
import ruamel.yaml
root_str = """\
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
"""
prepend_str = """\
pre_root:
- pre_class:
var1: c
"""
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4, sequence=4, offset=4)
root = yaml.load(root_str)
prepend = yaml.load(prepend_str)
这显然行不通:
new_str = {**prepend, **root}
这适用于我的情况,但看起来很老套:
import io
from contextlib import redirect_stdout
with io.StringIO() as buf, redirect_stdout(buf):
ruamel.yaml.dump(prepend, sys.stdout, Dumper=ruamel.yaml.RoundTripDumper)
ruamel.yaml.dump(root, sys.stdout, Dumper=ruamel.yaml.RoundTripDumper)
output = buf.getvalue()
with open("out.yaml", "w") as yaml_file:
yaml_file.write(output)
有几种方法可以使这更简单。首先你不应该混合
新 API ( yaml = ruamel.yaml.YAML()
) 与已弃用的旧 API ( ruamel.yaml.dump(....)
.
其次,您可以省略 contextlib
内容并直接流式传输到 BytesIO
(更好
比 StringIO
作为 YAML.dump()
写一个 UTF-8 流):
with io.BytesIO() as buf:
yaml.dump(prepend, buf)
yaml.dump(root, buf)
output = buf.getvalue()
with open("out.yaml", "wb") as yaml_file:
yaml_file.write(output)
sys.stdout.write(open("out.yaml").read())
给出:
pre_root:
- pre_class:
var1: c
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
您可以通过直接写入打开的文件来进一步简化此操作(请注意,在这两种情况下
已打开 "wb"
,因为 UTF-8):
with open("out.yaml", "wb") as yaml_file:
yaml.dump(prepend, yaml_file)
yaml.dump(root, yaml_file)
这会为您提供与之前相同的文件。
如果要保留root_str开头的块注释,应该
在数据级别合并:
# This also works in case prepend has multiple keys. When prepend
# and root have keys in common, you need to do something smarter
for key in reversed(prepend):
root.insert(0, key, prepend[key])
yaml.dump(root, sys.stdout)
给出:
# block comment
# block comment
# block comment
pre_root:
- pre_class:
var1: c
root:
- class:
- subclass:
var1: a
- class:
var2: b
如果您只想添加或附加 YAML 文件,为什么不使用像 new_str = '\n'.join([prepend_str, root_str])
.
这样的字符串呢?
但是,在 YAML 之前添加或附加可能会违反唯一键。
使用对象表示时,您还可以将其合并。
我用 ruamel.yaml
解决它的唯一方法是:
import sys
from ruamel.yaml import YAML
root_str = """\
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
"""
prepend_str = """\
pre_root:
- pre_class:
var1: c
"""
yaml = YAML()
root = yaml.load(root_str)
print("--- root: ----")
yaml.dump(root, sys.stdout)
# print(type(root))
# see methods of object:
# help(root)
prepend = yaml.load(prepend_str)
print("--- prepend: ----")
yaml.dump(prepend, sys.stdout)
def merge_into(base, mixin):
# compare the key sets for shared keys
bks = base.keys()
mks = mixin.keys()
if set(bks).intersection(mks):
print("Warning: Keys overlap! Aborted merge.")
print("\tbase keys:", bks)
print("\tmixin keys:", mks)
return
# append (without control of order)
for k in mks:
base[k] = mixin[k]
print("--- prepend merged into root: ----")
merge_into(root, prepend)
# does not work as expected
# root.insert(0, '', prepend, 'attached comment')
yaml.dump(root, sys.stdout)
然而,这只是简单地合并(实际上不是前置而是附加)并忽略混合中的任何注释。
打印输出为:
--- root: ----
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
--- prepend: ----
pre_root:
- pre_class:
var1: c
--- prepend merged into root: ----
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
pre_root:
- pre_class:
var1: c
我想将条目添加到带有注释的现有 yaml 文件的开头(或结尾,这无关紧要),我希望保留这些注释。有没有一种优雅的方法可以使用 ruamel.yaml
?
import sys
import ruamel.yaml
root_str = """\
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
"""
prepend_str = """\
pre_root:
- pre_class:
var1: c
"""
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4, sequence=4, offset=4)
root = yaml.load(root_str)
prepend = yaml.load(prepend_str)
这显然行不通:
new_str = {**prepend, **root}
这适用于我的情况,但看起来很老套:
import io
from contextlib import redirect_stdout
with io.StringIO() as buf, redirect_stdout(buf):
ruamel.yaml.dump(prepend, sys.stdout, Dumper=ruamel.yaml.RoundTripDumper)
ruamel.yaml.dump(root, sys.stdout, Dumper=ruamel.yaml.RoundTripDumper)
output = buf.getvalue()
with open("out.yaml", "w") as yaml_file:
yaml_file.write(output)
有几种方法可以使这更简单。首先你不应该混合
新 API ( yaml = ruamel.yaml.YAML()
) 与已弃用的旧 API ( ruamel.yaml.dump(....)
.
其次,您可以省略 contextlib
内容并直接流式传输到 BytesIO
(更好
比 StringIO
作为 YAML.dump()
写一个 UTF-8 流):
with io.BytesIO() as buf:
yaml.dump(prepend, buf)
yaml.dump(root, buf)
output = buf.getvalue()
with open("out.yaml", "wb") as yaml_file:
yaml_file.write(output)
sys.stdout.write(open("out.yaml").read())
给出:
pre_root:
- pre_class:
var1: c
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
您可以通过直接写入打开的文件来进一步简化此操作(请注意,在这两种情况下
已打开 "wb"
,因为 UTF-8):
with open("out.yaml", "wb") as yaml_file:
yaml.dump(prepend, yaml_file)
yaml.dump(root, yaml_file)
这会为您提供与之前相同的文件。
如果要保留root_str开头的块注释,应该 在数据级别合并:
# This also works in case prepend has multiple keys. When prepend
# and root have keys in common, you need to do something smarter
for key in reversed(prepend):
root.insert(0, key, prepend[key])
yaml.dump(root, sys.stdout)
给出:
# block comment
# block comment
# block comment
pre_root:
- pre_class:
var1: c
root:
- class:
- subclass:
var1: a
- class:
var2: b
如果您只想添加或附加 YAML 文件,为什么不使用像 new_str = '\n'.join([prepend_str, root_str])
.
但是,在 YAML 之前添加或附加可能会违反唯一键。 使用对象表示时,您还可以将其合并。
我用 ruamel.yaml
解决它的唯一方法是:
import sys
from ruamel.yaml import YAML
root_str = """\
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
"""
prepend_str = """\
pre_root:
- pre_class:
var1: c
"""
yaml = YAML()
root = yaml.load(root_str)
print("--- root: ----")
yaml.dump(root, sys.stdout)
# print(type(root))
# see methods of object:
# help(root)
prepend = yaml.load(prepend_str)
print("--- prepend: ----")
yaml.dump(prepend, sys.stdout)
def merge_into(base, mixin):
# compare the key sets for shared keys
bks = base.keys()
mks = mixin.keys()
if set(bks).intersection(mks):
print("Warning: Keys overlap! Aborted merge.")
print("\tbase keys:", bks)
print("\tmixin keys:", mks)
return
# append (without control of order)
for k in mks:
base[k] = mixin[k]
print("--- prepend merged into root: ----")
merge_into(root, prepend)
# does not work as expected
# root.insert(0, '', prepend, 'attached comment')
yaml.dump(root, sys.stdout)
然而,这只是简单地合并(实际上不是前置而是附加)并忽略混合中的任何注释。
打印输出为:
--- root: ----
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
--- prepend: ----
pre_root:
- pre_class:
var1: c
--- prepend merged into root: ----
# block comment
# block comment
# block comment
root:
- class:
- subclass:
var1: a
- class:
var2: b
pre_root:
- pre_class:
var1: c