最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How do I write out an anchor using ruamel.yaml? - Stack Overflow

programmeradmin0浏览0评论

I want to create data in python and write it to a file as a yaml-document using anchors and merges in the output.

I think this could be possible with ruamel YAML, because, as described in ruamels official examples:

  • it can load yaml-documents with anchors and merges transparently (transparent in the sense that access to the data is the same whether it is defined through anchors or not)
  • it can round-trip yaml-files while preserving anchors (so loading a yaml-file which includes anchors can be read and rewritten to disk and still have anchors)

This means ruamel.yaml must have an internal representation of the yaml-data that includes and understands anchors (unlike PyYAML, which only reads anchors but does not preserve them). There does not seem to be a documented way to create such anchors from python code.

The most minimal file I want to be able to create would look like this:

base: &ANCHOR
  x: 1

object:
  <<: *ANCHOR
  y: 2

I want to create data in python and write it to a file as a yaml-document using anchors and merges in the output.

I think this could be possible with ruamel YAML, because, as described in ruamels official examples:

  • it can load yaml-documents with anchors and merges transparently (transparent in the sense that access to the data is the same whether it is defined through anchors or not)
  • it can round-trip yaml-files while preserving anchors (so loading a yaml-file which includes anchors can be read and rewritten to disk and still have anchors)

This means ruamel.yaml must have an internal representation of the yaml-data that includes and understands anchors (unlike PyYAML, which only reads anchors but does not preserve them). There does not seem to be a documented way to create such anchors from python code.

The most minimal file I want to be able to create would look like this:

base: &ANCHOR
  x: 1

object:
  <<: *ANCHOR
  y: 2
Share Improve this question edited Mar 28 at 22:51 julaine asked Mar 28 at 8:41 julainejulaine 1,7561 gold badge14 silver badges31 bronze badges 3
  • 1 You should include a minimal example YAML document of the output that you want to create. Additionally you should make sure this round-trips without changes (if ruamel.yaml cannot round-trip it, it is far less likely you can generate it from scratch). – Anthon Commented Mar 28 at 8:59
  • @Anthon Good tip to say I can probably only create things I can roundtrip. – julaine Commented Mar 28 at 22:29
  • @Anthon After further consideration, I have added an example to the question (and deleted my comment arguing against the need for an example). Turns out the yaml-spec is much bigger than I thought and my question was therefore not as clear as I thought. – julaine Commented Mar 28 at 22:54
Add a comment  | 

1 Answer 1

Reset to default 1

When you round-trip your data using the following program:

import sys  
import ruamel.yaml

yaml_str = """\ 
base: &ANCHOR  
x: 1

object:  
<<: \*ANCHOR  
y: 2  
"""

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

you see that the output matches the input:

base: &ANCHOR
  x: 1

object:
  <<: *ANCHOR
  y: 2

You could actually create a new YAML instance for dumping and still get the same output. This means that the information about anchors and merging is somewhere in the data structure under data. So you should inspect various items.

print('anchor', data['base'].anchor)
print('type', type(data['base'].anchor))
print('keys', list(data['object'].keys()))
print('merge', data['object'].merge)
print('merge type', type(data['object'].merge))
print('ids', id(data['object'].merge[0][1]), id(data['base']))

which gives:

anchor Anchor('ANCHOR')
type <class 'ruamel.yaml.anchor.Anchor'>
keys ['y', 'x']
merge [(0, {'x': 1})]
merge type <class 'list'>
ids 4304434048 4304434048

The above is normally an incremental process (even for me, having some knowledge about the internals). And it helps to look at the source, especially construct_mapping in constructor.py and CommentedMap in comments. py

With the above information, lets first tackle the anchor ( you can have merges without anchor/alias, but they don't make much sense).

import sys
import ruamel.yaml

def CM(**kw):
    return ruamel.yamlments.CommentedMap(**kw)

common = CM(x=1)
common.yaml_set_anchor('ANCHOR')
data = CM(base=common, object=CM(tmp=common, y=2))
yaml = ruamel.yaml.YAML()
yaml.dump(data, sys.stdout)

which gives:

base: &ANCHOR
  x: 1
object:
  tmp: *ANCHOR
  y: 2

Creating the merge key, can be done by defining the CommentedMap with only the y key and adding the merge attribute:

import sys
import ruamel.yaml

def CM(**kw):
    return ruamel.yamlments.CommentedMap(**kw)

common = CM(x=1)
common.yaml_set_anchor('ANCHOR')
data = CM(base=common, object=CM(y=2))
setattr(data['object'], ruamel.yamlments.merge_attrib, [(0, common)])
yaml = ruamel.yaml.YAML()
yaml.dump(data, sys.stdout)

which gives:

base: &ANCHOR
  x: 1
object:
  <<: *ANCHOR
  y: 2
  1. There is no setter for the .merge attribute
  2. that attribute is a list of because in YAML the merge key can have have either a mapping or a list of mappings as value. IIRC the integer 0, determines the ordering.

Pin the version of ruamel.yaml you are using. Internals like these will change without notice

发布评论

评论列表(0)

  1. 暂无评论