使用pyyam生成具有覆盖的yaml锚定/引用

2024-10-02 08:18:38 发布

您现在位置:Python中文网/ 问答频道 /正文

使用人类编写的YAML可以做的一件事是:

foo: &foo_anchor
  key1: v1
  key2: v2
  key3: v3
bar:
  <<: *foo_anchor
  key2: override_value

我想用PyYAML编程生成这样的输出。看起来很棘手!默认情况下,据我所知,PyYAML只在遇到相等的对象时生成锚定/引用(顺序可能没有定义,而在本例中,bar必须引用foo,而不是相反)。我尝试了一些方法来定义YamlReference类,并在重写的Dumper.serialize_node方法中检查它的标记,但尝试执行如下操作:

        if node.tag.endswith('magic.prefix.YamlReference'):
            alias = node.value[0].value
            self.emit(yaml.events.AliasEvent(alias))
            super(Dumper, self).anchor_node(node.value[1])
            super(Dumper, self).serialize_node(node.value[1], parent, idx)

打乱了预期的事件流。这可能吗?你知道吗


Tags: 方法selfnode定义foovaluebaralias
2条回答

你可以这样做:

import yaml

class Merger(object):
  pass

def merger_representer(dumper, data):
  return dumper.represent_scalar(u'tag:yaml.org,2002:merge', '<<')

yaml.add_representer(Merger, merger_representer)

foo = {'key1': 'v1', 'key2': 'v2', 'key3': 'v3'}

root = {
  'foo': foo,
  'bar': {
     Merger(): foo,
     'key2': 'override_value'
  }
}

print(yaml.dump(root, sort_keys=False))

输出为:

foo: &id001
  key1: v1
  key2: v2
  key3: v3
bar:
  <<: *id001
  key2: override_value

sort_keys=False确保键的顺序正确,它需要Python>;=3.7和PyYAML>;=5.1(谢谢@tinita)。您无法控制生成的锚名称,但是这个YAML与您的相当。你知道吗

您需要Merger类来强制PyYAML发出<<(对于普通的字符串键,它将发出'<<',这样它就不会与合并键混淆)。你知道吗

实现这一点的一种方法是创建一个包含适当 有关合并信息的信息,并且仍然允许查找 data['bar']['key1']。当然,您需要使用适当的representer正确地转储这个类。你知道吗

这是什么鲁阿迈尔.亚马尔(免责声明我是 该包的作者)不允许合并地图的往返:

import sys
import ruamel.yaml

yaml_str = """\
foo: &foo_anchor
  key1: v1
  key2: v2
  key3: v3
bar:
  <<: *foo_anchor
  key2: override_value
"""

yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

它给出:

foo: &foo_anchor
  key1: v1
  key2: v2
  key3: v3
bar:
  <<: *foo_anchor
  key2: override_value

所以我建议你看一下类CommentedMap,以及它是怎样的 在constructor.pyrepresenter.py中处理。你知道吗

如果可以升级到ruamel.yaml,则可以执行以下操作:

cm = ruamel.yaml.comments.CommentedMap

data = cm()
data['foo'] = foo = cm(key1='v1', key2='v2', key3='v3')
foo.yaml_set_anchor('foo_anchor')
data['bar'] = bar = cm(key2='override_value')
bar.add_yaml_merge([(0, foo)])
yaml = ruamel.yaml.YAML()

yaml.dump(data, sys.stdout)

从零开始,你会得到一些类似的东西:

foo: &foo_anchor
  key1: v1
  key2: v2
  key3: v3
bar:
  <<: *foo_anchor
  key2: override_value

当然,以下工作与预期一样:

print(list(data['bar'].keys()))
print(data['bar']['key3'])

给予:

['key2', 'key1', 'key3']
v3

相关问题 更多 >

    热门问题