[英]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
不会从 YAML 映射/序列创建普通的 Python 字典/列表,而是创建其子类( CommentedMap
/ CommentedSeq
)并附加由这些容器中的前一个元素索引的注释。 同时,像__get__()
这样的 dunder 方法允许(大多数)正常使用这些容器在您的程序中使用和/或修改它们,然后转储它们。
ruamel.yaml
对字符串、整数、浮点数(以及某些扩展的布尔值)进行子类化,以保留 YAML 中可能出现的引号、指数、基数、任何锚点等信息。 但是如果将注释附加到标量,而不是它作为值或元素的容器,将导致在分配新值时丢失该注释。 也就是说,如果您有 YAML:
a: 18 # soon to be 55
b: 42
将其加载到data
并执行data['a'] = 55
您的评论将丢失。 不确定是否可以通过使容器更智能来改进这种行为,这值得研究,但前提是这样的标量是映射/序列的一部分。
除此之外None
不能被子类化,所以没有地方附加评论。 Booleans 也不能被子类化,但为了保留锚点ruamel.yaml
将ruamel.yaml
构造为int
的子类,这允许正常使用,例如在if
语句中测试真值。 然而None
的典型用法是测试身份(使用 `... is None`),而 AFAIK 没有办法伪造它。
所以.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
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.