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

7

我知道这与这个SO问题有关,但我最担心的是是否会影响保留的注释等内容。

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...
not
first_name: Art
last_name: Vandelay    # This is an occupation comment
occupation: Architect
about: Art Vandelay is a fictional character that George invents...
1个回答

4
在Python 2.7上以及至少具有ruamel.yaml 0.11.11的Python 3.X中,这可以很好地工作:
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, ...)

等等,什么??我不知道ruamel.ordereddict有.insert() :D - demux
3
可以理解,该软件包的作者在编写易于理解的文档方面以懒散著称。 - Anthon
看一下compat.py, line 12,似乎我只需要运行pip install ruamel.ordereddict。这个分析正确吗? - demux
3
现在这个功能已经包含在 ruamel.yaml 0.11.11 版本中,并且有相应的文档记录。感谢你的启发。 - Anthon
我用这个创建了一个钩子(hook),用于Python Schematics。目标是在保存时尽可能少地重新格式化yaml,但同时为新数据添加基本结构。 - demux
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接