使用 ruamel 保持 YAML 文件顺序

Keep YAML file order with ruamel

我正在尝试向 YAML 文件添加新元素,但我希望新元素能够保持视觉顺序,使文件更易于人类阅读。我很容易用 orderdict 来保持顺序,但是有了这个我们就得到了 !!omap 指令 "polluting" YAML 文件。 我希望新元素具有相同的顺序,在下面的代码中有 "yaml_doc" 示例。

有没有办法向 YAML 添加新元素,并在转储文件时保持顺序而不显示 omap 指令?

下面是我的代码和我得到的输出:

import sys
from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedSeq as cs
from ruamel.yaml.comments import TaggedScalar as ts
from ruamel.yaml.scalarstring import SingleQuotedScalarString as sq
from ruamel.ordereddict import ordereddict


yaml_doc = """\
version: 0
projects:
  - name: A1
    dir: B1
    aplan:
      when: ["X", "Y", "Z"]
    wflow: l
"""
yaml = YAML()
yaml.preserve_quotes = True
yaml.width = 4096
data = yaml.load(yaml_doc)

ref = data['projects']

record_to_add = dict(name='A2', dir='B2',
                     aplan=dict(when=["X", "Y", "Z"]), wflow='l')
ref.append(record_to_add)

record_to_add_2 = ordereddict([('name', 'A3'), ('dir', 'B3'), ('aplan', ordereddict(
    [('when', ['X', 'Y', 'Z'])])), ('wflow', 'l')])
ref.append(record_to_add_2)

yaml.dump(data, sys.stdout)

转储的输出

version: 0
projects:
- name: A1
  dir: B1
  aplan:
    when: ["X", "Y", "Z"]
  wflow: l
- aplan:
    when:
    - X
    - Y
    - Z
  wflow: l
  name: A2
  dir: B2
- !!omap
  - name: A3
  - dir: B3
  - aplan: !!omap
    - when:
      - X
      - Y
      - Z
  - wflow: l

为了保留键的顺序,ruamel.yaml 使用了 ordereddict 的子类,它 您可以在加载后立即使用 print(type(data)) 进行检查。那是一个CommentedMap 你应该像你那样创建那些 ordereddict:

import sys
from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedSeq as cs
from ruamel.yaml.comments import TaggedScalar as ts
from ruamel.yaml.scalarstring import SingleQuotedScalarString as sq
from ruamel.yaml.comments import CommentedMap as ordereddict


yaml_doc = """\
version: 0
projects:
  - name: A1
    dir: B1
    aplan:
      when: ["X", "Y", "Z"]
    wflow: l
"""
yaml = YAML()
yaml.preserve_quotes = True
yaml.width = 4096
data = yaml.load(yaml_doc)
# print(type(data['projects'][0])) # would give: <class 'ruamel.yaml.comments.CommentedMap'>

ref = data['projects']

record_to_add = dict(name='A2', dir='B2',
                     aplan=dict(when=["X", "Y", "Z"]), wflow='l')
ref.append(record_to_add)

record_to_add_2 = ordereddict([('name', 'A3'), ('dir', 'B3'), ('aplan', ordereddict(
    [('when', ['X', 'Y', 'Z'])])), ('wflow', 'l')])
ref.append(record_to_add_2)

yaml.dump(data, sys.stdout)

给出:

version: 0
projects:
- name: A1
  dir: B1
  aplan:
    when: ["X", "Y", "Z"]
  wflow: l
- name: A2
  dir: B2
  aplan:
    when:
    - X
    - Y
    - Z
  wflow: l
- name: A3
  dir: B3
  aplan:
    when:
    - X
    - Y
    - Z
  wflow: l

YAML spec 中明确提到了有序映射,这就是 Python ordereddict 在转储时映射到的内容(在加载时则相反)。 CommentedMap 还可以处理保留注释和节点属性。