Как вывести OrderedDict как файл YAML? - PullRequest
0 голосов
/ 20 декабря 2018

Я написал простой скрипт, который, наконец, использую 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 голосов
/ 20 декабря 2018

Когда вы загружаете файл YAML в режиме ruamel.yaml по умолчанию, то последовательность загружается в CommentedMap (определено в ruamel.yaml.comments.py).То, что CommentedMap является подклассом OrderedDict (или ruamel.ordereddict на Python2).

Итак, одну вещь, которую вы можете сделать, это преобразовать ваш 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)

с точно таким же результатом, как и раньше.

...