Allow our custom yaml dumper to NamespacedDictWrapper objects

This special dict class did not have a representer assigned to it, so
PyYAML would raise an exception when attempting to dump it.

This also removes the name overriding, as its implementation was
ill-conceived and will be deprecated in a later branch (it's only used
in this one place so deprecating should be of no-to-minimal impact).
This commit is contained in:
Erik Johnson 2018-08-29 14:13:07 -05:00
parent 5c723b06ac
commit d02ec34790
No known key found for this signature in database
GPG Key ID: 5E5583C437808F3F
3 changed files with 26 additions and 2 deletions

View File

@ -1357,11 +1357,11 @@ class LazyLoader(salt.utils.lazy.LazyDict):
''' '''
if '__grains__' not in self.pack: if '__grains__' not in self.pack:
self.context_dict['grains'] = opts.get('grains', {}) self.context_dict['grains'] = opts.get('grains', {})
self.pack['__grains__'] = salt.utils.context.NamespacedDictWrapper(self.context_dict, 'grains', override_name='grains') self.pack['__grains__'] = salt.utils.context.NamespacedDictWrapper(self.context_dict, 'grains')
if '__pillar__' not in self.pack: if '__pillar__' not in self.pack:
self.context_dict['pillar'] = opts.get('pillar', {}) self.context_dict['pillar'] = opts.get('pillar', {})
self.pack['__pillar__'] = salt.utils.context.NamespacedDictWrapper(self.context_dict, 'pillar', override_name='pillar') self.pack['__pillar__'] = salt.utils.context.NamespacedDictWrapper(self.context_dict, 'pillar')
mod_opts = {} mod_opts = {}
for key, val in list(opts.items()): for key, val in list(opts.items()):

View File

@ -17,6 +17,7 @@ except ImportError:
import yaml import yaml
import collections import collections
import salt.utils.context
from salt.utils.odict import OrderedDict from salt.utils.odict import OrderedDict
try: try:
@ -54,6 +55,14 @@ SafeOrderedDumper.add_representer(
collections.defaultdict, collections.defaultdict,
yaml.representer.SafeRepresenter.represent_dict yaml.representer.SafeRepresenter.represent_dict
) )
OrderedDumper.add_representer(
salt.utils.context.NamespacedDictWrapper,
yaml.representer.SafeRepresenter.represent_dict
)
SafeOrderedDumper.add_representer(
salt.utils.context.NamespacedDictWrapper,
yaml.representer.SafeRepresenter.represent_dict
)
if HAS_IOFLO: if HAS_IOFLO:
OrderedDumper.add_representer(odict, represent_ordereddict) OrderedDumper.add_representer(odict, represent_ordereddict)

View File

@ -7,6 +7,7 @@
from __future__ import absolute_import from __future__ import absolute_import
import os import os
import traceback import traceback
import yaml
# Import Salt Testing Libs # Import Salt Testing Libs
from tests.support.case import ShellCase from tests.support.case import ShellCase
@ -81,6 +82,20 @@ class OutputReturnTest(ShellCase):
ret = self.run_call('test.ping --out=yaml') ret = self.run_call('test.ping --out=yaml')
self.assertEqual(ret, expected) self.assertEqual(ret, expected)
def test_output_yaml_namespaced_dict_wrapper(self):
'''
Tests the ability to dump a NamespacedDictWrapper instance, as used in
magic dunders like __grains__ and __pillar__
See https://github.com/saltstack/salt/issues/49269
'''
dumped_yaml = '\n'.join(self.run_call('grains.items --out=yaml'))
loaded_yaml = yaml.load(dumped_yaml)
# We just want to check that the dumped YAML loades as a dict with a
# single top-level key, we don't care about the real contents.
assert isinstance(loaded_yaml, dict)
assert list(loaded_yaml) == ['local']
def test_output_unicodebad(self): def test_output_unicodebad(self):
''' '''
Tests outputter reliability with utf8 Tests outputter reliability with utf8