如何将OrderedDict转储为YAML文件?

时间:2018-12-20 18:41:58

标签: python yaml ruamel.yaml ordereddict

我编写了一个简单的脚本,最后使用ruamel.yaml将其发布到YAML文件中(如下所示的示例)。我使用了collections.OrderedDict,以便可以按字母顺序对键进行重新排序,但是即使使用json.load / json.dumps将其重新排序并转换回字典后,我也无法将其打印出来。有序的时尚。

我了解YAML规范并不关心顺序,但是我个人希望YAML文件排序,使用ruamel.yaml模块执行此操作的正确方法是什么?

logging.to_syslog: 'false'
statsbeat:
  multicast_interface_name: 'p1p1'
  primary_field_name: 'primary'
  udp_address: '239.253.0.50:20016'
  all_documents_index: 'statsall-${statsbeat.exchange_code}-${statsbeat.name}'
  exchange_code: 'd'
  primary_field_algorithm: 'range'
  cloud_type: 'none'
  primary_field_algorithm_range: '1-48'
  name: 'otpr'
logging.files:
  permissions: '0644'
  rotateeverybytes: 52428800
  keepfiles: 7
  name: '${statsbeat.name}.log'

1 个答案:

答案 0 :(得分:0)

ruamel.yaml的默认往返模式加载YAML文件时, 然后将序列加载到CommentedMap(在 ruamel.yaml.comments.py)。 CommentedMap是的子类 OrderedDict(或Python2上的ruamel.ordereddict)。

因此,您可以做的一件事就是将OrderedDict转换为CommentedMap

import sys
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap
from collections import OrderedDict

data = OrderedDict([
  ('logging.to_syslog', 'false'),
  ('statsbeat', OrderedDict([
    ('multicast_interface_name',  'p1p1'),
    ('primary_field_name',  'primary'),
    ('udp_address',  '239.253.0.50:20016'),
    ('all_documents_index',  'statsall-${statsbeat.exchange_code}-${statsbeat.name}'),
    ('exchange_code',  'd'),
    ('primary_field_algorithm',  'range'),
    ('cloud_type',  'none'),
    ('primary_field_algorithm_range',  '1-48'),
    ('name',  'otpr'),
  ])),
  ('logging.files', OrderedDict([
    ('permissions',  '0644'),
    ('rotateeverybytes',  52428800),
    ('keepfiles',  7),
    ('name',  '${statsbeat.name}.log'),
  ])),
])

def comseq(d):
    if isinstance(d, OrderedDict):
        cs = CommentedMap()
        for k, v in d.items():
            cs[k] = comseq(v)
        return cs
    return d


data = comseq(data)


yaml = ruamel.yaml.YAML()
yaml.dump(data, sys.stdout)

给出:

logging.to_syslog: 'false'
statsbeat:
  multicast_interface_name: p1p1
  primary_field_name: primary
  udp_address: 239.253.0.50:20016
  all_documents_index: statsall-${statsbeat.exchange_code}-${statsbeat.name}
  exchange_code: d
  primary_field_algorithm: range
  cloud_type: none
  primary_field_algorithm_range: 1-48
  name: otpr
logging.files:
  permissions: '0644'
  rotateeverybytes: 52428800
  keepfiles: 7
  name: ${statsbeat.name}.log

(如果您希望像示例中那样使用多余的单引号,则可以强制转换字符串 从SingleQuotedScalarString导入到ruamel.yaml.scalarstring


但是可能更容易的是指示代表 代表OrderedDict的方式与CommentedMap相同。假设 与data相同的导入和定义,您可以这样做:

from ruamel.yaml.representer import RoundTripRepresenter

class MyRepresenter(RoundTripRepresenter):
    pass

ruamel.yaml.add_representer(OrderedDict, MyRepresenter.represent_dict, 
                            representer=MyRepresenter)

yaml = ruamel.yaml.YAML()
yaml.Representer = MyRepresenter

yaml.dump(data, sys.stdout)

结果与以前完全相同。