Is there a way to preserve order while round-trip dumping YAML in Python?

人盡茶涼 提交于 2021-01-28 07:54:55

问题


I am trying to load some data from a YAML-file and put it back:

services:
  dc01:
    sw-06-50001:
      servers:
      - {ip: 10.255.206.12, port: 50001, weight: 100}
      - {ip: 10.255.206.13, port: 50001, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50001}
    sw-09-50002:
      servers:
      - {ip: 10.255.206.18, port: 50002, weight: 100}
      - {ip: 10.255.206.19, port: 50002, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50002}
    sw-06-50003:
      servers:
      - {ip: 10.255.206.12, port: 50003, weight: 100}
      - {ip: 10.255.206.13, port: 50003, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50003}
    sw-09-50004:
      servers:
      - {ip: 10.255.206.18, port: 50004, weight: 100}
      - {ip: 10.255.206.19, port: 50004, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50004}

with this:

import ruamel.yaml as yaml
with open('filename.yml', 'r') as stream:
    outdata = yaml.load(stream,Loader=yaml.Loader)

yaml.dump(outdata,'filename_out.yml')

I need to preserve all the formatting and data order in the list, but the output dump results in a sorting in alphabetical order by the sw-xx.. key:

services:
  dc01:
    sw-06-50001:
      servers:
      - {ip: 10.255.206.12, port: 50001, weight: 100}
      - {ip: 10.255.206.13, port: 50001, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50001}

    sw-06-50003:
      servers:
      - {ip: 10.255.206.12, port: 50003, weight: 100}
      - {ip: 10.255.206.13, port: 50003, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50003}
    sw-09-50002:
      servers:
      - {ip: 10.255.206.18, port: 50002, weight: 100}
      - {ip: 10.255.206.19, port: 50002, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50002}
    sw-09-50004:
      servers:
      - {ip: 10.255.206.18, port: 50004, weight: 100}
      - {ip: 10.255.206.19, port: 50004, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50004}

How could I keep an original order of the entries while dumping?


回答1:


You are doing a round-trip, but you are not using ruamel.yaml's round-trip feature. Instead you are using the outdated PyYAML compatibility load and dump functions.

Instead you should instantiate a ruamel.yaml.YAML() instance and use that instance's load and dump methods, they default to round-trip with preservation of order (and comments, tag names, etc.)

import sys
import ruamel.yaml

yaml_str = """\
services:
  dc01:
    sw-06-50001:  # first
      servers:
      - {ip: 10.255.206.12, port: 50001, weight: 100}
      - {ip: 10.255.206.13, port: 50001, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50001}
    sw-09-50002:
      servers:
      - {ip: 10.255.206.18, port: 50002, weight: 100}
      - {ip: 10.255.206.19, port: 50002, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50002}
    sw-06-50003:  # third
      servers:
      - {ip: 10.255.206.12, port: 50003, weight: 100}
      - {ip: 10.255.206.13, port: 50003, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50003}
    sw-09-50004:
      servers:
      - {ip: 10.255.206.18, port: 50004, weight: 100}
      - {ip: 10.255.206.19, port: 50004, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50004}
"""

yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
# yaml.preserve_quotes = True
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

which gives:

services:
  dc01:
    sw-06-50001:  # first
      servers:
      - {ip: 10.255.206.12, port: 50001, weight: 100}
      - {ip: 10.255.206.13, port: 50001, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50001}
    sw-09-50002:
      servers:
      - {ip: 10.255.206.18, port: 50002, weight: 100}
      - {ip: 10.255.206.19, port: 50002, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50002}
    sw-06-50003:  # third
      servers:
      - {ip: 10.255.206.12, port: 50003, weight: 100}
      - {ip: 10.255.206.13, port: 50003, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50003}
    sw-09-50004:
      servers:
      - {ip: 10.255.206.18, port: 50004, weight: 100}
      - {ip: 10.255.206.19, port: 50004, weight: 90}
      virtual: {ip: 192.168.1.4, port: 50004}

Or in case you have your YAML in a file:

from pathlib import Path
from ruamel.yaml import YAML

# the recommended extension for YAML files has been .yaml since 2006.
file_name = Path('filename.yaml')  
file_out = Path('filename_out.yaml')

yaml = YAML()
outdata = yaml.load(file_name)
yaml.dump(outdata, file_out)


来源:https://stackoverflow.com/questions/61989767/is-there-a-way-to-preserve-order-while-round-trip-dumping-yaml-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!