summaryrefslogtreecommitdiff
path: root/lib/ansible/parsing/yaml/constructor.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/parsing/yaml/constructor.py')
-rw-r--r--lib/ansible/parsing/yaml/constructor.py41
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