Python 使用另一个yaml文件的内容更新yaml文件

Python 使用另一个yaml文件的内容更新yaml文件,python,python-2.7,yaml,pyyaml,ruamel.yaml,Python,Python 2.7,Yaml,Pyyaml,Ruamel.yaml,设置: 我有两个YAML文件:一个是带有标记和别名的大文件,另一个是带有大文件中一些键值对的小文件。我用的是python2.7 问题: 我想用小文件中的值更新大文件中的值 挑战: 小yaml可以包含大yaml中存在的键值对的任意组合。我还必须保留大的文本结构(而不是解析标记/别名)。大的一个很复杂,包含字典的字典列表的字典(不要问…)。这可能吗 特别是在以下方面: resources: &something that_thing: some_stuff some_other_

设置:
我有两个YAML文件:一个是带有标记和别名的大文件,另一个是带有大文件中一些键值对的小文件。我用的是python2.7

问题:
我想用小文件中的值更新大文件中的值

挑战:
小yaml可以包含大yaml中存在的键值对的任意组合。我还必须保留大的文本结构(而不是解析标记/别名)。大的一个很复杂,包含字典的字典列表的字典(不要问…)。这可能吗

特别是在以下方面:

resources: &something
   that_thing: some_stuff
   some_other_stuff: this_thing
我想得到的,例如:

resources: &something
   that_thing: some_stuff
   some_other_stuff: this_thing_updated

如果小文件的键在大文件中是唯一的,那么这并不适合dict(我认为?

如果键:

import sys
import ruamel.yaml

big_yaml = """\
resources: &something
   that_thing: !SomeStuff 
      a:
      - 1
      - some_stuff: d
      b: *something
   some_other_stuff: this_thing
"""

small_yaml = """\
some_stuff: 42
some_other_stuff: 'the_other_thing'
"""

def walk_tree(d, update, done=set()):
    if not update:
        return
    if id(d) in done:
        return
    if isinstance(d, dict):
        done.add(id(d))
        for k in d:
            if k in update:
                d[k] = update.pop(k)
                continue  # don't recurse in the newly updated value
            walk_tree(d[k], update)  # recurse into the values
    elif isinstance(d, list):
        done.add(id(d))
        for elem in d:
            walk_tree(elem, update)
    # doing nothing for leaf-node scalars


yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=2, sequence=2, offset=0)
yaml.preserve_quotes = True
big = yaml.load(big_yaml)
small = yaml.load(small_yaml)
# print(data)
walk_tree(big, small)

yaml.dump(big, sys.stdout)
其中:

resources: &something
  that_thing: !SomeStuff
    a:
    - 1
    - some_stuff: 42
    b: *something
  some_other_stuff: 'the_other_thing'
请注意:

  • 您需要保留节点的
    id
    s集,以防止无限递归。当然,只有在大数据是递归的情况下,这才是必要的,但这不会有什么坏处
  • I
    pop
    更新
    的值,因此小文件变为空,递归提前停止。如果要更新所有匹配的键,则不要弹出,只需分配(然后可以从
    漫游树中删除前两行)
  • 即使程序不知道如何创建
    ,标记也会被保留!一些东西
    类。这是一种魔力
  • 当前仅当存在引用锚的实际别名时才转储锚。锚点是保留的,因此可以对
    ruamel.yaml
    进行修补,以始终转储锚点(通常,在添加在数据树中多次表示的新元素时,这可能会导致冲突并需要额外检查)
  • 关于“另一件事”的多余引用被保留下来
  • 您的映射响应。序列缩进必须一致,否则会重新格式化。您可以取消注释
    yaml.indent
    行并调整值(以匹配大文件)

或者,您可以有一个小YAML,如下所示:

[resources, that_thing, a, 1, some_stuff]: 42
[resources, some_other_stuff]: 'the_other_thing'
然后,您可以基于键序列元素对数据结构进行确定性递归,无需检查ID和拖动
update
(只需将该值作为
walk\u树的第二个参数传入即可)



如果所有更新都在大文件的顶层。那么,这些递归都是不必要的,因为这只是上面的一个简单例子。

如果键值对必须存在于大键值对中,则不需要更新。我假设你的意思是,这个键必须存在于这个大的键中,并且它的值会随着这个小的键的值而更新。大文件中的小文件的密钥在哪里?在顶层,或者在树中的任何位置(在这种情况下,它们在大文件中也必须是全局“唯一的”,以便更新它们)。大文件中的所有锚点都有别名吗?。。。只是想表达我的感激之情。我认为这是难以置信的,有多少人在他们的答案上付出了努力。