1

我编写了一个简单的脚本,最终使用 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'
4

1 回答 1

1

当您以ruamel.yaml的默认往返模式加载 YAML 文件时,会将一个序列加载到CommentedMap(在 中定义 ruamel.yaml.comments.py)中。那CommentedMapOrderedDict(或ruamel.ordereddict在 Python2 上)的子类。

因此,您可以做的一件事是将您的转换OrderedDictCommentedMap

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与 a 相同的方式表示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)

结果与以前完全相同。

于 2018-12-20T20:01:45.413 回答