pyyaml icon indicating copy to clipboard operation
pyyaml copied to clipboard

Deep construction doesn't take into account merged or referenced anchors

Open m-schubert opened this issue 7 years ago • 1 comments

For a YAML file like so:

test:
  &anchor
  foo: 2
  bar:
    - a
    - b
    - c

merge_test:
  - !merge_test
    <<: *anchor

If I try to construct a merge_test object using deep mapping:

import yaml

def merge_test_constructor(loader, node):
    m = loader.construct_mapping(node, deep=True)
    print "Merge test constructor gets map %s." % m

yaml.add_constructor(u'!merge_test', merge_test_constructor)

The bar sequence doesn't seem to get populated:

> yaml.load(open('merge_test.yml'))
Merge test constructor gets map {'foo': 2, 'bar': []}.

This appears to be because the test object is already constructed (without deep construction), and thus construct_object() in constructor.py simply returns its cached copy:

    def construct_object(self, node, deep=False):
        if node in self.constructed_objects:
            return self.constructed_objects[node]

m-schubert avatar Nov 22 '17 09:11 m-schubert

I was able to work around this by making a custom loader that always does deep construction by default:

class MyLoader(yaml.SafeLoader):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Do deep construction by default so that anchors are expanded
        # before custom constructors are called
        self.deep_construct = True


d = yaml.load(f, Loader=MyLoader)

JPEWdev avatar Aug 12 '22 21:08 JPEWdev