diff options
Diffstat (limited to 'lib/ansible/parsing/yaml/constructor.py')
-rw-r--r-- | lib/ansible/parsing/yaml/constructor.py | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/lib/ansible/parsing/yaml/constructor.py b/lib/ansible/parsing/yaml/constructor.py index d1a2a01bc2..541165a42f 100644 --- a/lib/ansible/parsing/yaml/constructor.py +++ b/lib/ansible/parsing/yaml/constructor.py @@ -19,9 +19,17 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from yaml.constructor import Constructor +from yaml.constructor import Constructor, ConstructorError +from yaml.nodes import MappingNode from ansible.parsing.yaml.objects import AnsibleMapping, AnsibleSequence, AnsibleUnicode +try: + from __main__ import display +except ImportError: + from ansible.utils.display import Display + display = Display() + + class AnsibleConstructor(Constructor): def __init__(self, file_name=None): self._ansible_file_name = file_name @@ -35,10 +43,33 @@ class AnsibleConstructor(Constructor): data.ansible_pos = self._node_position_info(node) def construct_mapping(self, node, deep=False): - ret = AnsibleMapping(super(Constructor, self).construct_mapping(node, deep)) - ret.ansible_pos = self._node_position_info(node) - - return ret + # This first part fixes a problem with pyyaml's handling of duplicate + # dict keys. + # from SafeConstructor + if not isinstance(node, MappingNode): + raise ConstructorError(None, None, + "expected a mapping node, but found %s" % node.id, + node.start_mark) + self.flatten_mapping(node) + mapping = AnsibleMapping() + for key_node, value_node in node.value: + key = self.construct_object(key_node, deep=deep) + try: + hash(key) + except TypeError as exc: + raise ConstructorError("while constructing a mapping", node.start_mark, + "found unacceptable key (%s)" % exc, key_node.start_mark) + + if key in mapping: + display.warning('While constructing a mapping%s found a duplicate dict key (%s). Using last value only.' % (node.start_mark, key_node.start_mark)) + + value = self.construct_object(value_node, deep=deep) + mapping[key] = value + + # Add our extra information to the returned value + mapping.ansible_pos = self._node_position_info(node) + + return mapping def construct_yaml_str(self, node): # Override the default string handling function |