我可以在ruamel.yaml的CommentedMap中插入一行吗?

时间:2016-05-01 17:40:19

标签: python yaml ordereddictionary ruamel.yaml

我知道这与this SO question有关,但我最关心的是这是否会混淆诸如保存的评论等​​内容。

import ruamel.yaml as yaml

yaml_str = """\
first_name: Art
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...
"""

data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)

# I'd like to extend CommentedMap so that I can do something like:
data.insert(1, 'last_name', 'Vandelay')

print(yaml.dump(data, Dumper=yaml.RoundTripDumper))
应输出:
first_name: Art
last_name: Vandelay
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...
应该输出:
first_name: Art
last_name: Vandelay    # This is an occupation comment
occupation: Architect
about: Art Vandelay is a fictional character that George invents...

1 个答案:

答案 0 :(得分:4)

在Python 2.7和Python 3.X上,至少ruamel.yaml 0.11.11,这很好用:

import ruamel.yaml

yaml_str = """\
first_name: Art
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...
"""

data = ruamel.yaml.round_trip_load(yaml_str)
data.insert(1, 'last name', 'Vandelay')

print(ruamel.yaml.round_trip_dump(data))

给出:

first_name: Art
last name: Vandelay
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...

因为行尾注释与CommentedMap中行的键相关联。 (Linux Mint上的Python 2.7.11,使用ruamel.yaml 0.11.10。)

这不适用于旧版本的ruamel.yaml和Python3,因为您正在使用的.insert()是完整版ruamel.ordereddict的一个功能,标准库中的OrderedDict并没有这样做。有这种方法。因此,您需要将.insert()函数移植到CommentedMap

import ruamel.yaml
from ruamel.yaml.comments import CommentedMap
from ruamel.yaml.compat import ordereddict

yaml_str = """\
first_name: Art
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...
"""

def com_insert(self, pos, key, value, comment=None):
    od = ordereddict()
    od.update(self)
    for k in od:
        del self[k]
    for index, old_key in enumerate(od):
        if pos == index:
            self[key] = value
        self[old_key] = od[old_key]
    if comment is not None:
        self.yaml_add_eol_comment(comment, key=key)

CommentedMap.insert = com_insert

data = ruamel.yaml.round_trip_load(yaml_str)
data.insert(1, 'last name', 'Vandelay', comment="new key")

print(ruamel.yaml.round_trip_dump(data))

给出了Python3:

first_name: Art
last name: Vandelay    # new key
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...

请注意,insert()有一个可选参数,允许您为新插入的键值对指定注释。上述方法有效,因为从CommentedMap删除密钥并不会删除与密钥关联的注释。所以我暂时将旧的键值对保留在od中 删除所有键值,然后将它们复制回来,在适当的时候插入新的东西

上面的insert带有注释,已添加到ruamel.yaml 0.11.11中 Python 2和3

.round_trip_load()相当于.load(...., Loader=ruamel.yaml.RoundTripLoader, ...).round_trip_dump()相当于`.dump(.....,Dumper = ruamel.yaml.RoundTripDumper,allow_unicode = True,...)