在使用 ruamel.yaml 格式化时保留仅带有注释的 YAML 文件?
Preserve YAML files with only comments when formatting using ruamel.yaml?
我想在 YAML 文件中保留只有评论的评论。使用我当前的设置,ruamel.yaml 在格式化此类文件时输出 null。有没有好的方法来做到这一点?这是我目前所拥有的:
from ruamel.yaml import YAML
def round_trip(sout, sin, idt):
yaml = YAML()
assert idt >= 2
yaml.indent(mapping=idt, sequence=idt, offset=idt-2)
yaml.preserve_quotes = True
data = yaml.load(sin)
if data is not None:
yaml.dump(data, sout)
else:
print("the file is empty") # needs fixing: should dump original file
评论未保留,因为您的实例上没有位置 data
把它们。在往返模式下 ruamel.yaml
不会创建正常 Python
dicts/lists 来自 YAML mappings/sequences,但其子类
(CommentedMap
/CommentedSeq
) 并附上由前一个索引的评论
这些容器中的元素。同时,像 __get__()
这样的 dunder 方法
允许(大多数)正常使用这些容器以使用和/或修改它们
你的程序,然后转储它们。
ruamel.yaml
对字符串、整数、浮点数进行子类化(并且在某种程度上
布尔值)以保留引号、指数、基数、任何
YAML 中可能出现的锚点等。但如果评论是
附加到标量,而不是它作为值的容器或
元素,将导致在分配新值时丢失该注释。那
如果你有 YAML:
a: 18 # soon to be 55
b: 42
将其加载到 data
并执行 data['a'] = 55
您的评论将会丢失。它是
不确定是否可以通过制作容器来改进这种行为
更聪明,值得研究,但前提是这样的标量是 mapping/sequence.
的一部分
除此之外None
不能被子类化,所以没有地方附加
注释。布尔值也不能被子类化,但要保留锚 ruamel.yaml
将布尔值构造为 int
的子类,它允许正常使用,例如在
if
语句测试真值。 None
的典型用法
但是正在测试身份(使用 `... is None``)并且据我所知,没有办法伪造它。
所以 .load()
没有办法给你回复有评论的东西
信息。但是你确实使用了 YAML()
实例,IMO 最好是
保留评论信息的子类。它目前存储了一些
有关上次加载文档的信息,例如文件 YAML 版本
如果提供指令 (%YAML 1.1
)
import sys
import ruamel.yaml
yaml_str = """\
# this document is, by default,
# round-tripped to null
"""
class YAML(ruamel.yaml.YAML):
def load(self, stream):
if not hasattr(stream, 'read') and hasattr(stream, 'open'):
# pathlib.Path() instance
data = super().load(stream)
if data is None:
buf = stream.read_text()
elif isinstance(stream, str):
data = super().load(stream)
buf = stream
else: # buffer stream data
buf = stream.read()
data = super().load(buf)
if data is None and buf.strip():
self._empty_commented_doc = buf
return data
def dump(self, data, stream=None, transform=None):
# dump to stream or Path
if not hasattr(self, '_empty_commented_doc'): # the simple case
return super().dump(data, stream=stream, transform=transform)
# doesn't handle transform
if not hasattr(stream, 'read') and hasattr(stream, 'open'):
with stream.open('w') as fp:
fp.write(self._empty_commented_doc)
super().dump(data, stream)
else:
stream.write(self._empty_commented_doc)
if data is not None:
super().dump(data, stream)
yaml = YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
# yaml.preserve_quotes = True
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)
data = True
print('----------------')
yaml.dump(data, sys.stdout)
给出:
# this document is, by default,
# round-tripped to null
----------------
# this document is, by default,
# round-tripped to null
true
...
上面的内容也可以扩展为处理根级标量文档,并且
我正在考虑向 ruamel.yaml. 添加更完整的实现
我想在 YAML 文件中保留只有评论的评论。使用我当前的设置,ruamel.yaml 在格式化此类文件时输出 null。有没有好的方法来做到这一点?这是我目前所拥有的:
from ruamel.yaml import YAML
def round_trip(sout, sin, idt):
yaml = YAML()
assert idt >= 2
yaml.indent(mapping=idt, sequence=idt, offset=idt-2)
yaml.preserve_quotes = True
data = yaml.load(sin)
if data is not None:
yaml.dump(data, sout)
else:
print("the file is empty") # needs fixing: should dump original file
评论未保留,因为您的实例上没有位置 data
把它们。在往返模式下 ruamel.yaml
不会创建正常 Python
dicts/lists 来自 YAML mappings/sequences,但其子类
(CommentedMap
/CommentedSeq
) 并附上由前一个索引的评论
这些容器中的元素。同时,像 __get__()
这样的 dunder 方法
允许(大多数)正常使用这些容器以使用和/或修改它们
你的程序,然后转储它们。
ruamel.yaml
对字符串、整数、浮点数进行子类化(并且在某种程度上
布尔值)以保留引号、指数、基数、任何
YAML 中可能出现的锚点等。但如果评论是
附加到标量,而不是它作为值的容器或
元素,将导致在分配新值时丢失该注释。那
如果你有 YAML:
a: 18 # soon to be 55
b: 42
将其加载到 data
并执行 data['a'] = 55
您的评论将会丢失。它是
不确定是否可以通过制作容器来改进这种行为
更聪明,值得研究,但前提是这样的标量是 mapping/sequence.
除此之外None
不能被子类化,所以没有地方附加
注释。布尔值也不能被子类化,但要保留锚 ruamel.yaml
将布尔值构造为 int
的子类,它允许正常使用,例如在
if
语句测试真值。 None
的典型用法
但是正在测试身份(使用 `... is None``)并且据我所知,没有办法伪造它。
所以 .load()
没有办法给你回复有评论的东西
信息。但是你确实使用了 YAML()
实例,IMO 最好是
保留评论信息的子类。它目前存储了一些
有关上次加载文档的信息,例如文件 YAML 版本
如果提供指令 (%YAML 1.1
)
import sys
import ruamel.yaml
yaml_str = """\
# this document is, by default,
# round-tripped to null
"""
class YAML(ruamel.yaml.YAML):
def load(self, stream):
if not hasattr(stream, 'read') and hasattr(stream, 'open'):
# pathlib.Path() instance
data = super().load(stream)
if data is None:
buf = stream.read_text()
elif isinstance(stream, str):
data = super().load(stream)
buf = stream
else: # buffer stream data
buf = stream.read()
data = super().load(buf)
if data is None and buf.strip():
self._empty_commented_doc = buf
return data
def dump(self, data, stream=None, transform=None):
# dump to stream or Path
if not hasattr(self, '_empty_commented_doc'): # the simple case
return super().dump(data, stream=stream, transform=transform)
# doesn't handle transform
if not hasattr(stream, 'read') and hasattr(stream, 'open'):
with stream.open('w') as fp:
fp.write(self._empty_commented_doc)
super().dump(data, stream)
else:
stream.write(self._empty_commented_doc)
if data is not None:
super().dump(data, stream)
yaml = YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
# yaml.preserve_quotes = True
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)
data = True
print('----------------')
yaml.dump(data, sys.stdout)
给出:
# this document is, by default,
# round-tripped to null
----------------
# this document is, by default,
# round-tripped to null
true
...
上面的内容也可以扩展为处理根级标量文档,并且 我正在考虑向 ruamel.yaml. 添加更完整的实现