使用 Ruamel 插入密钥
Insert a key using Ruamel
我正在使用 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 有序地图。
有没有简单的方法来做到这一点?另外,我可以简单地以某种方式插入到数据结构中吗?
如果您 round_trip ruamel.yaml
¹ 中的映射,则映射不会表示为 collections.OrderedDict()
,而是表示为 ruamel.yaml.comments.CommentedMap()
。后者可以是 collections.OrderedDict()
的子类,具体取决于您使用的 Python 版本(例如,在 Python 2 中,它使用来自 ruamel.ordereddict
的更快的 C 实现)
表示器不会自动将 "normal" 有序字典(无论是来自 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 as well as ruamel.ordereddict。
我正在使用 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 有序地图。
有没有简单的方法来做到这一点?另外,我可以简单地以某种方式插入到数据结构中吗?
如果您 round_trip ruamel.yaml
¹ 中的映射,则映射不会表示为 collections.OrderedDict()
,而是表示为 ruamel.yaml.comments.CommentedMap()
。后者可以是 collections.OrderedDict()
的子类,具体取决于您使用的 Python 版本(例如,在 Python 2 中,它使用来自 ruamel.ordereddict
的更快的 C 实现)
表示器不会自动将 "normal" 有序字典(无论是来自 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 as well as ruamel.ordereddict。