使用Python ruamel.yaml,在往返模式下加载时失去锚点吗?

时间:2018-11-20 15:56:41

标签: python ruamel.yaml

加载包含不同嵌套级别的锚点的文件时,锚点似乎丢失了,并且密钥保持为空。

加载以下文件时:

---
Dict1:
    - InnerDict: &inner
            key: val

Dict2:
    InnerDict:
        <<: *inner

Dict3:
    - InnerDict:
        <<: *inner
...

...包含代码(Python 3.7,ruamel.yaml版本0.15.78):

from ruamel.yaml import YAML
with open("file.yaml") as infile:
    content = YAML(typ='rt', pure=True).load(infile)
print(content)

...给出:

{'Dict1': [ordereddict([('InnerDict', ordereddict([('key', 'val')]))])],
 'Dict2': ordereddict([('InnerDict', ordereddict())]),
 'Dict3': [ordereddict([('InnerDict', ordereddict([('key', 'val')]))])]}

... Dict2的内部字典为空。

在安全模式下,两种情况下的锚都将按预期方式解释。

它是故意的还是一个错误?

1 个答案:

答案 0 :(得分:0)

那绝对是一个错误,这与广度优先有关 在数据结构中构建映射。到时候 InnerDict下的Dict2被构造,其中一个嵌套在Dict1下 不完全可用。 InnerDict下的Dict3位于 相同的深度,因此可以正确构造( 如果您删除Dict1结构中的破折号,请先合并 使锚点出现在较浅的位置)。

除了安装ruamel.yaml>=0.15.79外,解决此问题的一种方法是 提供替代的构造函数,该结构强制进行深度优先处理:

import sys
import ruamel.yaml

class MyConstructor(ruamel.yaml.constructor.RoundTripConstructor):
    def construct_yaml_map(self, node):
        data = ruamel.yaml.comments.CommentedMap()
        data._yaml_set_line_col(node.start_mark.line, node.start_mark.column)
        yield data
        self.construct_mapping(node, data, deep=True)
        self.set_collection_style(data, node)

MyConstructor.add_constructor(
    u'tag:yaml.org,2002:map', MyConstructor.construct_yaml_map
)


yaml = ruamel.yaml.YAML()
yaml.Constructor = MyConstructor


yaml_str = """\
Dict1:
    - InnerDict: &inner
            key: val

Dict2:
    InnerDict:
        <<: *inner

Dict3:
    - InnerDict:
        <<: *inner
"""

data = yaml.load(yaml_str)
for k in data:
   print(k, data[k])
print('---------')
yaml.dump(data, sys.stdout)

正在生成:

Dict1 [ordereddict([('InnerDict', ordereddict([('key', 'val')]))])]
Dict2 ordereddict([('InnerDict', ordereddict([('key', 'val')]))])
Dict3 [ordereddict([('InnerDict', ordereddict([('key', 'val')]))])]
---------
Dict1:
- InnerDict: &inner
    key: val

Dict2:
  InnerDict:
    <<: *inner

Dict3:
- InnerDict:
    <<: *inner

(由于data的转储是正确的,即使没有上述“补丁”,此 测试往返时以前未检测到