简体   繁体   English

使用 ruamel.yaml 时,如何防止重新格式化 yaml 文件?

[英]How can I prevent re-formating of a yaml file when ruamel.yaml is used?

I am using solution in the related answer for How to auto-dump modified values in nested dictionaries using ruamel.yaml .我在如何使用 ruamel.yaml 自动转储嵌套字典中的修改值的相关答案中使用解决方案。

I have observe that when self.update(self.yaml.load(f) or {}) is called: it keeps reformatting the yaml file by sorting it based on the alphabetic order and changes its indention into 2.我观察到当self.update(self.yaml.load(f) or {})被调用时:它通过根据字母顺序对其进行排序来不断重新格式化yaml文件并将其缩进更改为 2。

=> Would it be possible to prevent reformatting? => 可以防止重新格式化吗?

I have also tried following line, which did not make any affect on it in order to keep indention as 4 space:我还尝试了以下行,这对它没有任何影响,以便将缩进保持为 4 个空格:

yaml = YAML(typ="safe")
yaml.indent(mapping=2, sequence=4, offset=2)
yaml.default_flow_style = False

config.yaml: config.yaml:

c:  # my comment
    b:  
      f: 5  
      e: 22  
a:
    z: 4
    b: 4  # my comment

code (exactly same code from How to auto-dump modified values in nested dictionaries using ruamel.yaml ):代码(与How to auto-dump modified values in nested dictionaries using ruamel.yaml 中的代码完全相同):

#!/usr/bin/env python3

import sys
import os
from pathlib import Path
import ruamel.yaml


class SubConfig(dict):
    def __init__(self, parent):
        self.parent = parent

    def updated(self):
        self.parent.updated()

    def __setitem__(self, key, value):
        if isinstance(value, dict):
            v = SubConfig(self)
            v.update(value)
            value = v
        super().__setitem__(key, value)
        self.updated()

    def __getitem__(self, key):
        try:
            res = super().__getitem__(key)
        except KeyError:
            super().__setitem__(key, SubConfig(self))
            self.updated()
            return super().__getitem__(key)
        return res

    def __delitem__(self, key):
        res = super().__delitem__(key)
        self.updated()

    def update(self, *args, **kw):
        for arg in args:
            for k, v in arg.items():
                self[k] = v
        for k, v in kw.items():
            self[k] = v
        self.updated()
        return


_SR = ruamel.yaml.representer.SafeRepresenter
_SR.add_representer(SubConfig, _SR.represent_dict)


class Config(dict):
    def __init__(self, filename, auto_dump=True):
        self.filename = filename if hasattr(filename, "open") else Path(filename)
        self.auto_dump = auto_dump
        self.changed = False
        self.yaml = ruamel.yaml.YAML(typ="safe")
        self.yaml.default_flow_style = False
        if self.filename.exists():
            with open(filename) as f:
                self.update(self.yaml.load(f) or {})

    def updated(self):
        if self.auto_dump:
            self.dump(force=True)
        else:
            self.changed = True

    def dump(self, force=False):
        if not self.changed and not force:
            return
        with open(self.filename, "w") as f:
            self.yaml.dump(dict(self), f)
        self.changed = False

    def __setitem__(self, key, value):
        if isinstance(value, dict):
            v = SubConfig(self)
            v.update(value)
            value = v
        super().__setitem__(key, value)
        self.updated()

    def __getitem__(self, key):
        try:
            res = super().__getitem__(key)
        except KeyError:
            super().__setitem__(key, SubConfig(self))
            self.updated()
        return super().__getitem__(key)

    def __delitem__(self, key):
        res = super().__delitem__(key)
        self.updated()

    def update(self, *args, **kw):
        for arg in args:
            for k, v in arg.items():
                self[k] = v
        for k, v in kw.items():
            self[k] = v
        self.updated()


cfg = Config(Path("config.yaml"))

=> config.yaml file is updated as follows, where, its sorted and indention changed into 2, and comments are removed: => config.yaml文件更新如下,其中排序和缩进变为2,并去掉注释:

a:
  b: 4
  z: 4
c:
  b:
    e: 5
    f: 22

It is not possible to prevent indentation "reformatting".无法防止缩进“重新格式化”。 ruamel.yaml is documented to normalize the formatting so that all (block style) mappings are indented the same, and all (block style) sequences are indented the same. ruamel.yaml被记录为规范化格式,以便所有(块样式)映射缩进相同,所有(块样式)序列缩进相同。 You can however set each of these, which you don't seem to do for the mappings (the representation for Python dict s in YAML):但是,您可以设置其中的每一个,您似乎没有为映射执行这些操作(YAML 中 Python dict的表示):

import sys
import ruamel.yaml

data = dict(a=dict(b=[42, 18]))

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4, sequence=4, offset=2)
yaml.dump(data, sys.stdout)

which gives indentation of four for both mappings and sequences:它为映射和序列提供了四个缩进:

a:
    b:
      - 42
      - 18

Make sure to use the default (round-trip) loader/dumper to prevent sorting and to give you full control over indenting the output.确保使用默认(往返)加载程序/转储程序以防止排序并让您完全控制 output 的缩进。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM