python - 使用 ruamel 保留合并键和显式键的相对顺序

标签 python yaml ruamel.yaml

我希望使用 ruamel.yaml 对大型人工编辑的 YAML 文件执行一些自动编辑。

输入文件包含合并键,如下所示:

foo: &foo
  color: red

bar:
  name: qux
  <<: *foo

如果可能,我想保留显式 name 的相对顺序。键和 <<合并键,但看起来鲁梅尔确实希望合并键放在第一位。这是我通过 ruamel 往返此 YAML 时得到的结果:

foo: &foo
  color: red

bar:
  <<: *foo
  name: qux

有什么方法可以告诉 ruamel 保留此 block 中合并键的位置吗?

最佳答案

通过调整表示器中的两条线来进行映射 可以修复,合并键的位置信息就在那里, 它只是没有被使用。不幸的是,这是一个相当大的函数 需要一些导入:

import sys
import ruamel.yaml

if ruamel.yaml.version_info < (0, 15, 86):
    from ruamel.yaml.nodes import MappingNode, ScalarNode
    from ruamel.yaml.comments import comment_attrib, merge_attrib

    def represent_mapping(self, tag, mapping, flow_style=None):
        value = []
        try:
            flow_style = mapping.fa.flow_style(flow_style)
        except AttributeError:
            flow_style = flow_style
        try:
            anchor = mapping.yaml_anchor()
        except AttributeError:
            anchor = None
        node = MappingNode(tag, value, flow_style=flow_style, anchor=anchor)
        if self.alias_key is not None:
            self.represented_objects[self.alias_key] = node
        best_style = True
        # no sorting! !!
        try:
            comment = getattr(mapping, comment_attrib)
            node.comment = comment.comment
            if node.comment and node.comment[1]:
                for ct in node.comment[1]:
                    ct.reset()
            item_comments = comment.items
            for v in item_comments.values():
                if v and v[1]:
                    for ct in v[1]:
                        ct.reset()
            try:
                node.comment.append(comment.end)
            except AttributeError:
                pass
        except AttributeError:
            item_comments = {}
        merge_list = [m[1] for m in getattr(mapping, merge_attrib, [])]
        merge_pos = getattr(mapping, merge_attrib, [[0]])[0][0]          # <<<<<<<< line added
        item_count = 0
        if bool(merge_list):
            items = mapping.non_merged_items()
        else:
            items = mapping.items()
        for item_key, item_value in items:
            item_count += 1
            node_key = self.represent_key(item_key)
            node_value = self.represent_data(item_value)
            item_comment = item_comments.get(item_key)
            if item_comment:
                assert getattr(node_key, 'comment', None) is None
                node_key.comment = item_comment[:2]
                nvc = getattr(node_value, 'comment', None)
                if nvc is not None:  # end comment already there
                    nvc[0] = item_comment[2]
                    nvc[1] = item_comment[3]
                else:
                    node_value.comment = item_comment[2:]
            if not (isinstance(node_key, ScalarNode) and not node_key.style):
                best_style = False
            if not (isinstance(node_value, ScalarNode) and not node_value.style):
                best_style = False
            value.append((node_key, node_value))
        if flow_style is None:
            if ((item_count != 0) or bool(merge_list)) and self.default_flow_style is not None:
                node.flow_style = self.default_flow_style
            else:
                node.flow_style = best_style
        if bool(merge_list):
            # because of the call to represent_data here, the anchors
            # are marked as being used and thereby created
            if len(merge_list) == 1:
                arg = self.represent_data(merge_list[0])
            else:
                arg = self.represent_data(merge_list)
                arg.flow_style = True
            value.insert(merge_pos, (ScalarNode(u'tag:yaml.org,2002:merge', '<<'), arg))   # <<<<< line changed
        return node

    ruamel.yaml.representer.RoundTripRepresenter.represent_mapping = represent_mapping



yaml_str = """\
foo: &foo
  color: red

bar:
  name: qux
  <<: *foo
"""

yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

给出:

foo: &foo
  color: red

bar:
  name: qux
  <<: *foo

上面尝试保持绝对位置,不进行删除 或插入键值对。

使用下一版本时,上述内容不会修补任何内容 ruamel.yaml,其中将包含这些更改。

关于python - 使用 ruamel 保留合并键和显式键的相对顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54204865/

相关文章:

json - Helm 为 nginx 模板转换数据

python - 如何使用 ruamel.yaml 添加节点

python - 如何使用Python3将ruamel.yaml转换为dict?

python - 在 Python 中更改函数的关键字默认值

ruby-on-rails - i18n 在 Ruby on Rails 上, < 和 > 被替换为 &gt ; <不打算的时候

java - 如何在 Spring Boot 中的 YML 文件中创建条件属性?

python - ruamel_yaml.constructor.ConstructorError : could not determine a constructor for the tag 'tag:yaml.org,2002:python/tuple' in "<unicode string>"

python - Pandas - 根据另一个单元格的先前值填充 NaN

python - Azure DevOps 和 Pywinauto,在 Azure Pipelines 中运行测试时出现 TimeoutErrors

python - Django ConnectionAbortedError + 类型错误 + 属性错误