I am trying to use anchored data passed thru a constructor in an alias however the alias wants to use the pre-constructor data.
I've taken inspiration from anthon's Is there a way to construct an object using PyYAML construct_mapping after all nodes complete loading? but still found no joy.
Below is some sample code:
class L2D(dict):
def __repr__(self):
return('L2D({})'.format(dict.__repr__(self)))
def l2d_constructor(loader, node):
print("constructing")
instance = L2D.__new__(L2D)
yield instance
state = loader.construct_sequence(node, deep=True)
instance.__init__(state)
yaml.add_constructor(u'!l2d', l2d_constructor)
print(yaml.load('''
a: !l2d
- [e, f]
- [g, h]
'''))
print("============")
print(yaml.load('''
a: &other !l2d
- [e, f]
- [g, h]
b:
<<: *other
a: b
c: d
'''))
The first load works but while I'd expect the second loads output to be
constructing
{'a': L2D({'g': 'h', 'e': 'f'}), 'b': {'a': 'b', 'g': 'h', 'e': 'f', 'c': 'd'}}
instead I get
constructing
Traceback (most recent call last):
File "test2.py", line 41, in <module>
'''))
File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/main.py", line 86, in load
return loader.get_single_data()
File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 56, in get_single_data
return self.construct_document(node)
File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 65, in construct_document
for dummy in generator:
File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 494, in construct_yaml_map
value = self.construct_mapping(node)
File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 265, in construct_mapping
self.flatten_mapping(node)
File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 240, in flatten_mapping
% subnode.id, subnode.start_mark)
ruamel.yaml.constructor.ConstructorError: while constructing a mapping
in "<unicode string>", line 8, column 3:
<<: *other
^ (line: 8)
expected a mapping for merging, but found sequence
in "<unicode string>", line 5, column 5:
- [e, f]
^ (line: 5)
The constructing
print suggests that the constructor has done it's work but my suspicion is that the alias it trying to get the data from the unaltered yaml tree rather then the resulting data from the constructor.
Is there any way I can make this work?
In order to use the merge feature of YAML your anchored "type" needs to be a mapping (Python dict
) and the key/value pairs of that mapping are inserted in the other mapping at the point where you do:
<<: *other
Your anchored type is a sequence, and that is not allowed when using the merge feature.
You should review the merge documentation, where you can see that the anchored type always are mappings.