我正在使用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有序地图。
有一种简单的方法吗?另外,我可以简单地以某种方式插入数据结构吗?
答案 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的作者。