【问题标题】:How to automatically add a reference with ruamel.yaml?如何使用 ruamel.yaml 自动添加引用?
【发布时间】:2017-10-02 10:34:04
【问题描述】:

我前段时间问了一个非常相似的question,但我仍然对如何在 YAML 转储中添加引用感到困惑。

我的目标是在默认值上添加锚点,以最大程度地减少转储上的冗余。所以我写了这个:

import collections
import ruamel.yaml as yaml

default = {'a': 1, 'b': 2, 'c': 3}

data = {
    (1,2,3,4): {1: {'a': 10}, 2: {'b': 20}},
    (5,6,7,8): {1: {}, 2: {'a': 100, 'b': 200, 'c': 300}},
}

d = yaml.comments.CommentedMap()
d.update(default)
d.yaml_set_anchor('default')
default = d

for m, a in data.items():
    for k in a.keys():
        u = yaml.comments.CommentedMap()
        u.update(a[k])
        u.add_yaml_merge([(0, default)])
        a[k] = u

data[None] = default

def my_key_repr(self, data):
    if isinstance(data, tuple):
        return self.represent_sequence(u'tag:yaml.org,2002:seq', data, flow_style=True)
    return yaml.representer.SafeRepresenter.represent_key(self, data)

yaml.representer.RoundTripRepresenter.represent_key = my_key_repr

print yaml.dump(data, Dumper=yaml.RoundTripDumper, width=100, allow_unicode=True,
                explicit_start=True)

预期的输出是:

---
~: &default
  a: 1
  c: 3
  b: 2
[1, 2, 3, 4]:
  1:
    <<: *default
    a: 10
  2:
    <<: *default
    b: 20
[5, 6, 7, 8]:
  1:
    <<: *default
  2:
    <<: *default
    a: 100
    c: 300
    b: 200

我得到的是:

---
?
: &default
  a: 1
  c: 3
  b: 2
[1, 2, 3, 4]:
  1:
    <<: *default
    a: 10
  2:
    <<: *default
    b: 20
&id001 [5, 6, 7, 8]:
  1:
    <<: *id001
  2:
    <<: *id001
    a: 100
    c: 300
    b: 200

*id001 不知从何而来...

【问题讨论】:

  • 如果您实际上希望 [1, 2, 3, 4] 作为键而不是 abc,则需要将键指定为 yaml.comments.CommentedSeq((1, 2, 3, 4))CommentedSeq() 的参数可以是一个列表,它的值在创建时被复制。

标签: python yaml ruamel.yaml


【解决方案1】:

这里有几个问题:

  • 如果您希望密钥 foobar 出现在您的输出中,您必须在源代码中的某处指定它们。

  • 如果您希望您的 YAML 文档是隐式的(即不以 --- 开头),那么您不应指定 explicit_start=True

  • 为 None 的键被转储为? 而不是~

  • 如果您使用 update()dict 填充 CommentedMap()(即有序字典),则不能期望以特定顺序添加键。如果您希望密钥按acb 的顺序排列(如您所指),您必须确保这是它们呈现给CommentedMap() 的顺序

  • 由于您的顶级data 未排序,因此无法保证在您的YAML 文档中顶级映射是null 键(? :~:)。

    李>

以下内容:

from ruamel import yaml

d = {'a': 1, 'b': 2, 'c': 3}

abc = yaml.comments.CommentedMap()
abc['a'] = 100
abc['c'] = 300
abc['b'] = 200

base = [
    ('foo', {1: {'a': 10}, 2: {'b': 20}}),
    ('bar', {1: {}, 2: abc}),
]

data = yaml.comments.CommentedMap()
default = yaml.comments.CommentedMap()
for m, a in base:
    data[m] = a
for k in sorted(d):
    default[k] = d[k]
default.yaml_set_anchor('default')


for m, a in data.items():
    for k in sorted(a.keys()):
        u = yaml.comments.CommentedMap()
        u.update(a[k])
        u.add_yaml_merge([(0, default)])
        a[k] = u

data.insert(0, None, default)

x = yaml.round_trip_dump(data, width=100).replace('?\n:', '~:')
print(x)

准确地给出您期望的输出。

【讨论】:

  • 我的错误,我忘记添加导致问题的代码。请更新我的信息。
  • 噢噢噢!我想我找到了解决方案。我需要使用comments.CommentedKeySeq 选项
  • @nowox 是的,你需要那个。弄清楚这些事情的最好方法(如果你不想在 Stack Overflow 上问她)是通过 round_trip_load-ing 你的目标 YAML 是什么,然后打印你想要的特殊事情的 type()加载。我会更新我的答案,但我这周要去旅行,可能要到下一次才有时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-10
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
  • 2017-06-29
相关资源
最近更新 更多