英文:
ruamel yaml cloning a node without merging anchors
问题
我理解你想要的是如何在YAML文件中进行深度复制并修改节点名称。下面是你提供的代码的翻译部分:
import copy
import sys
import ruamel.yaml
yaml_str = """
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
"""
def main():
yaml = ruamel.yaml.YAML(typ='rt')
original_yaml = yaml.load(yaml_str)
copied_stanza = copy.deepcopy(original_yaml['dev'])
original_yaml['stage'] = copied_stanza
yaml.dump(original_yaml, sys.stdout)
if __name__ == "__main__":
main()
请注意,这只是代码的翻译部分,我不会回答关于代码的问题。如果你有任何其他翻译需求,请告诉我。
英文:
I have a YAML file with a similar structure:
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
What I'm trying to achieve is cloning the node dev
by performing a deep copy of all its properties - including the merge operator - and changing its name to stage
.
The desired result is the following:
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
stage:
<<: *base
key3: test
I've tried doing this using ruamel.yaml
library by running the following code snippet:
import copy
import sys
import ruamel.yaml
yaml_str = """\
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
"""
def main():
yaml = ruamel.yaml.YAML(typ='rt')
original_yaml = yaml.load(yaml_str)
copied_stanza = copy.deepcopy(original_yaml['dev'])
original_yaml['stage'] = copied_stanza
yaml.dump(original_yaml, sys.stdout)
if __name__ == "__main__":
main()
However I get the following result:
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
stage:
<<:
key1: test
key2: test
key3: test
key1: test
key2: test
which is different from what I want since it's flattening the merge operator in a very weird way.
I believe the issue is the way I'm copying the node, however I've tried searching the web for hours and tried a plethora of different approaches without any luck.
Any advice?
UPDATE
After Anthon's answer, I was able to get closer to the desired result.
However if the node that I'm trying to copy has one more level of depth (see dev.key4
in this example):
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
key4:
subkey1: test
then the generated yaml will start creating anchors and aliases for all those nested nodes:
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
key4: &id001
subkey1: test
stage:
<<: *base
key3: test
key4: *id001
How can I avoid the creation of those?
UPDATE 2
I adapted the solution provided by Anthon to handle any level of depth using a recursive function:
import sys
import ruamel.yaml
yaml_str = """\
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
key4:
subkey1: test
"""
def create_copied_stanza(dev):
copied_stanza = ruamel.yaml.comments.CommentedMap()
for k, v in dev.items():
if k in dev._ok:
if isinstance(v, ruamel.yaml.comments.CommentedMap): # Add your condition here
copied_stanza[k] = create_copied_stanza(v)
else:
copied_stanza[k] = v
return copied_stanza
def main():
yaml = ruamel.yaml.YAML(typ='rt')
original_yaml = yaml.load(yaml_str)
dev = original_yaml['dev']
copied_stanza = create_copied_stanza(dev)
copied_stanza._yaml_merge = dev._yaml_merge
original_yaml['stage'] = copied_stanza
yaml.dump(original_yaml, sys.stdout)
if __name__ == "__main__":
main()
答案1
得分: 1
以下是翻译好的部分:
"Your YAML 中的映射被加载为 ruamel.yaml.comments.CommentedMap
实例,并且它们实现了 __deepcopy__
,以便保留合并键。
为了获得您想要的结果,您目前需要复制映射拥有的键以及包含合并信息的属性。
请确保固定您的 ruamel.yaml
版本,因为这些内部实现可能会在将来更改。
如果您的合并键不在根级别,您需要编写一个递归处理任何映射的函数,但对于您的 YAML,这不是必要的。"
请注意,代码部分未被翻译,仅提供文本内容。
英文:
The mappings in your YAML are loaded as ruamel.yaml.comments.CommentedMap
instances and they
have __deepcopy__
implemented just so as to preserve the merge key.
To get what you want you currently need to copy the keys owned by the
mapping and the attribute that contains the merge information.
Make sure to pin your ruamel.yaml
version as these internals might change
in the future.
import sys
import ruamel.yaml
yaml_str = """\
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
"""
yaml = ruamel.yaml.YAML(typ='rt')
original_yaml = yaml.load(yaml_str)
dev = original_yaml['dev']
copied_stanza = ruamel.yaml.comments.CommentedMap({k: v for k, v in dev.items() if k in dev._ok})
copied_stanza._yaml_merge = dev._yaml_merge
original_yaml['stage'] = copied_stanza
yaml.dump(original_yaml, sys.stdout)
which gives:
main: &base
key1: test
key2: test
dev:
<<: *base
key3: test
stage:
<<: *base
key3: test
If your merge key is not at the root level, you have to make a function that does this for you, recursing in
any mappings,
but for your YAML this is not necessary.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论