【问题标题】:Preserve YAML files with only comments when formatting using ruamel.yaml?使用 ruamel.yaml 格式化时保留仅带有注释的 YAML 文件?
【发布时间】:2020-11-24 21:00:39
【问题描述】:

我想在 YAML 文件中只保留 cmets。使用我当前的设置,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

【问题讨论】:

    标签: python yaml ruamel.yaml


    【解决方案1】:

    没有保留 cmets,因为您的实例上没有位置 data 把它们。在往返模式下ruamel.yaml 不会创建普通的 Python 来自 YAML 映射/序列的字典/列表,但它们的子类 (CommentedMap/CommentedSeq) 并附加上一个索引的 cmets 这些容器中的元素。同时,dunder 方法如__get__() 允许(大多数)正常使用这些容器来使用和/或修改它们 你的程序,然后转储它们。

    ruamel.yaml 子类化字符串、整数、浮点数(并且在某种程度上扩展 booleans) 以保留有关报价、指数、基数、任何 您的 YAML 中可能出现的锚点等。但是如果 cmets 是 附加到一个标量,而不是它是一个值的容器或 元素,将导致对分配新值的注释丢失。那 是如果你有 YAML:

    a: 18  # soon to be 55
    b: 42
    

    将其加载到data 并执行data['a'] = 55 您的评论将会丢失。它是 不确定是否可以通过制作容器来改善这种行为 更聪明,值得研究,但前提是这样的标量是映射/序列的一部分。

    除了None不能被子类化,所以没地方附上 厘米。布尔值也不能被子类化,但要保留锚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
    ...
    

    上述内容也可以扩展为处理根级别的标量文档,并且 我正在考虑向 ruamel.yaml 添加更完整的实现。

    【讨论】:

      猜你喜欢
      • 2021-12-24
      • 2021-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-10
      • 2021-09-26
      • 2020-05-30
      相关资源
      最近更新 更多