ruamel.yaml - 如何在 ruamel.yaml 中显式写入两个引用

标签 ruamel.yaml

如果我有多个引用,当我使用 Python 中的 ruaml.yaml 将它们写入 YAML 文件时,我得到:

  <<: [*name-name, *help-name]

但我更愿意拥有

<<: *name-name
<<: *help-name

是否可以选择在写入文件时实现此目的?

更新

descriptions:
  - &description-one-ref
    description: >

helptexts:
  - &help-one
    help_text: |

questions:
  - &question-one
    title: "title test"
    reference: "question-one-ref"
    field: "ChoiceField"
    choices:
      - "Yes"
      - "No"
    required: true
    <<: *description-one-ref
    <<: *help-one
    riskvalue_max: 10
    calculations:
      - conditions:
          - comparator: "equal"
            value: "Yes"
        actions:
          - riskvalue: 0
      - conditions:
          - comparator: "equal"
            value: "No"
        actions:
          - riskvalue: 10

目前我正在读取这样的文件并在 python 中修改特定值,然后想将其写回。当我写作时,我发现引用文献是列表而不是概述的问题。

这意味着工作流程如下:我正在通过

阅读文档
yaml = ruamel.yaml.YAML()
with open('test.yaml') as f:
    data = yaml.load(f)

for k in data.keys():
    if k == 'questions':
        q = data.get(k)
        for i in range(0, len(q)):
            q[i]['title'] = "my new title"

f.close()
g = open('new_file.yaml', 'w')
yaml(data)
g.close()

最佳答案

不,没有这样的选项,因为它会导致无效的 YAML 文件。

<<是一个映射键,其值被解释 特别假设解析器实现了 language independent merge key specification .并且映射键必须是唯一的 根据YAML specification :

The content of a mapping node is an unordered set of key: value node pairs, with the restriction that each of the keys is unique.

那个ruamel.yaml (< 0.15.75) 不会抛出这样的错误 重复键是 bug .在重复的普通键上,ruamel.yaml 确实会引发错误。该错误继承自 PyYAML(不是 符合规范,即使在 复制普通键)。


然而,通过一些预处理和后处理,你想做的就可以 很容易实现。诀窍是在解析之前使 YAML 有效 通过制作有问题的副本 <<键唯一(但可识别) 然后,在将 YAML 写回文件时,用这些替换 <<: * 的唯一键再次。在下面第一次出现 <<: *[<<, 0]: 取代, 第二个 [<<, 1]:

*需要成为替代的一部分,因为没有 anchor 这些别名的文档。

import sys
import subprocess
import ruamel.yaml

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.indent(sequence=4, offset=2)

class DoubleMergeKeyEnabler(object):
    def __init__(self):
        self.pat = '<<: '  # could be at the root level mapping, so no leading space
        self.r_pat = '[<<, {}]: '   # probably not using sequences as keys
        self.pat_nr = -1

    def convert(self, doc):
        while self.pat in doc:
            self.pat_nr += 1
            doc = doc.replace(self.pat, self.r_pat.format(self.pat_nr), 1)
        return doc

    def revert(self, doc):
        while self.pat_nr >= 0:
            doc = doc.replace(self.r_pat.format(self.pat_nr), self.pat, 1)
            self.pat_nr -= 1
        return doc


dmke = DoubleMergeKeyEnabler()

with open('test.yaml') as fp:
  # we don't do this line by line, that would not work well on flow style mappings
  orgdoc = fp.read()
  doc = dmke.convert(orgdoc)

data = yaml.load(doc)
data['questions'][0].anchor.always_dump = True
#######################################
# >>>> do your thing on data here <<< #
#######################################

with open('output.yaml', 'w') as fp:
    yaml.dump(data, fp, transform=dmke.revert)

res = subprocess.check_output(['diff', '-u', 'test.yaml', 'output.yaml']).decode('utf-8')
print('diff says:', res)

给出:

diff says:

这意味着文件在往返过程中是相同的(只要你不 在倾销之前改变任何东西)。

设置preserve_quotes并调用 ident()YAML 上实例是必要的 保留你多余的引号,resp。保持缩进。

自 anchor question-one没有别名,您需要通过以下方式显式启用转储 设置 always_dump将该属性设置为 True。如有必要,您可以递归 走过去data并设置 anchor.always_dump = True什么时候.anchor.value is not None

关于ruamel.yaml - 如何在 ruamel.yaml 中显式写入两个引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52851168/

相关文章:

python - Yaml 结束 ("...") 即使 yaml.explicit_end=False 也总是被转储

python - ruamel.yaml 自定义 CommentedMapping 用于自定义标签

python - 如何转储带有前导零的 int 的 YAML?

python-3.x - 如何在不破坏 ruamel.yaml 中的 anchor 的情况下更改序列中的锚定标量?

python - 内嵌评论 ruamel.yaml

python - 使用 Python 在 YAML 中获取重复键

ruamel.yaml - 如何往返 ruamel.yaml 字符串,如 "on"

python - 将 YAML 反序列化回 Python 对象

python - 如何对齐 ruamel.yaml 中的 eol 注释,以便它们都位于同一列中

python - 如何在不更改文件缩进的情况下使用 ruamel.yaml 包编辑 yaml 文件?