使用Ruamel插入密钥

时间:2016-09-03 14:22:11

标签: ruamel.yaml

我正在使用Ruamel Python库以编程方式编辑人工编辑的YAML文件。源文件具有按字母顺序排序的键。

我不确定这是一个基本的Python问题,还是Ruamel问题,但我尝试对Ruamel的OrderedDict结构进行排序的所有方法都失败了。

我很困惑,例如,为什么基于this recipe的以下代码无法正常工作:

import ruamel.yaml
import collections

def read_file(f):
    with open(f, 'r') as _f:
        return ruamel.yaml.round_trip_load(
            _f.read(),
            preserve_quotes=True
        )

def write_file(f, data):
    with open(f, 'w') as _f:
        _f.write(ruamel.yaml.dump(
            data,
            Dumper=ruamel.yaml.RoundTripDumper,
            explicit_start=True,
            width=1024
        ))

data = read_file('in.yaml')
data = collections.OrderedDict(sorted(data.items(), key=lambda t: t[0]))
write_file('out.yaml', data)

但是考虑到这个输入文件:

---
bananas: 1
apples: 2

生成以下输出文件:

--- !!omap
- apples: 2
- bananas: 1

即。它把我的文件变成了YAML有序地图。

有一种简单的方法吗?另外,我可以简单地以某种方式插入数据结构吗?

1 个答案:

答案 0 :(得分:4)

如果您对ruamel.yaml¹中的映射进行round_trip,则映射不会表示为collections.OrderedDict(),它会表示为ruamel.yaml.comments.CommentedMap()。后者可以是collections.OrderedDict()的子类,具体取决于您使用的Python版本(例如,在Python 2中,它使用来自ruamel.ordereddict的更快的C实现)

表示者不会自动将“正常”有序词典(无论是来自collections还是ruamel.ordereddict)解释为round_trip_dump模式中的特殊词典。但是,如果你放弃collections

import ruamel.yaml

def read_file(f):
    with open(f, 'r') as _f:
        return ruamel.yaml.round_trip_load(
            _f.read(),
            preserve_quotes=True
        )

def write_file(f, data):
    with open(f, 'w') as _f:
        ruamel.yaml.dump(
            data,
            stream=_f,
            Dumper=ruamel.yaml.RoundTripDumper,
            explicit_start=True,
            width=1024
        )

data = read_file('in.yaml')
data = ruamel.yaml.comments.CommentedMap(sorted(data.items(), key=lambda t: t[0]))
write_file('out.yaml', data)

您的out.yaml将是:

---
apples: 2
bananas: 1

请注意,我还删除了write_file例程中的低效率。如果您未指定流,则所有数据将首先(在内存中)流式传输到StringIO实例,然后返回(您使用_f.write()将其写入流中,效率更高直接写入流。

至于你的最后一个问题:是的,你可以使用以下方式插入:

data.insert(1, 'apricot', 3)

¹免责声明:我是ruamel.yaml以及ruamel.ordereddict的作者。