def compose_mapping_node(self, anchor): start_event = self.get_event() tag = start_event.tag if tag is None or tag == u'!': tag = self.resolve(MappingNode, None, start_event.implicit) node = MappingNode(tag, [], start_event.start_mark, None, flow_style=start_event.flow_style, comment=start_event.comment, anchor=anchor) if anchor is not None: self.anchors[anchor] = node while not self.check_event(MappingEndEvent): # key_event = self.peek_event() item_key = self.compose_node(node, None) # if item_key in node.value: # raise ComposerError("while composing a mapping", # start_event.start_mark, # "found duplicate key", key_event.start_mark) item_value = self.compose_node(node, item_key) # node.value[item_key] = item_value node.value.append((item_key, item_value)) end_event = self.get_event() if node.flow_style is True and end_event.comment is not None: node.comment = end_event.comment node.end_mark = end_event.end_mark self.check_end_doc_comment(end_event, node) return node
def compose_mapping_node(self, anchor): # type: (Any) -> Any start_event = self.parser.get_event() tag = start_event.tag if tag is None or tag == u'!': tag = self.resolver.resolve(MappingNode, None, start_event.implicit) node = MappingNode(tag, [], start_event.start_mark, None, flow_style=start_event.flow_style, comment=start_event.comment, anchor=anchor) if anchor is not None: self.anchors[anchor] = node while not self.parser.check_event(MappingEndEvent): # key_event = self.parser.peek_event() item_key = self.compose_node(node, None) # if item_key in node.value: # raise ComposerError("while composing a mapping", # start_event.start_mark, # "found duplicate key", key_event.start_mark) item_value = self.compose_node(node, item_key) # node.value[item_key] = item_value node.value.append((item_key, item_value)) end_event = self.parser.get_event() if node.flow_style is True and end_event.comment is not None: node.comment = end_event.comment node.end_mark = end_event.end_mark self.check_end_doc_comment(end_event, node) return node
def represent_mapping(self, tag, mapping, flow_style=None): value = [] node = MappingNode(tag, value, flow_style=flow_style) if self.alias_key is not None: self.represented_objects[self.alias_key] = node best_style = True if hasattr(mapping, 'items'): # if it's a syaml_dict, preserve OrderedDict order. # Otherwise do the default thing. sort = not isinstance(mapping, syaml_dict) mapping = list(mapping.items()) if sort: mapping.sort() for item_key, item_value in mapping: node_key = self.represent_data(item_key) node_value = self.represent_data(item_value) if not (isinstance(node_key, ScalarNode) and not node_key.style): best_style = False if not (isinstance(node_value, ScalarNode) and not node_value.style): best_style = False value.append((node_key, node_value)) if flow_style is None: if self.default_flow_style is not None: node.flow_style = self.default_flow_style else: node.flow_style = best_style return node
def represent_ordereddict(dumper, data): value = [] for item_key, item_value in data.items(): node_key = dumper.represent_data(item_key) node_value = dumper.represent_data(item_value) value.append((node_key, node_value)) return MappingNode("tag:yaml.org,2002:map", value)
def revert_mappings(node): r""" Undo the effect of simplify_mappings. """ from ruamel.yaml.nodes import SequenceNode, MappingNode, ScalarNode if isinstance(node, MappingNode): if node.tag.startswith(YAML_TAG_REWRITE_MAP): tag = node.tag[len(YAML_TAG_REWRITE_MAP ):] or "tag:yaml.org,2002:seq" node = SequenceNode( tag=tag, value=[ MappingNode(tag="tag:yaml.org,2002:map", value=[ (ScalarNode(tag="tag:yaml.org,2002:str", value="key", start_mark=key.start_mark, end_mark=key.end_mark), revert_mappings(key)), (ScalarNode(tag="tag:yaml.org,2002:str", value="value", start_mark=value.start_mark, end_mark=value.end_mark), revert_mappings(value)), ], start_mark=key.start_mark, end_mark=value.end_mark) for (key, value) in node.value ], start_mark=node.start_mark, end_mark=node.end_mark, comment=node.comment, anchor=node.anchor) else: node.value = [(revert_mappings(key), revert_mappings(value)) for (key, value) in node.value] elif isinstance(node, SequenceNode): node.value = [revert_mappings(value) for value in node.value] return node
def simplify_mappings(node): r""" Cereal saves a map very explicitly as a list of key value pairs, i.e.,`[{key: "abc", value: 1}, {key: "def", value: 2}]`. For JSON that's very reasonable since keys cannot have arbitrary types but in YAML we do not have that limitation so we detect and rewrite such mappings. """ from ruamel.yaml.nodes import SequenceNode, MappingNode, ScalarNode def to_key_value(pairs): if len(pairs) != 2: return False key, value = pairs if len(key) != 2: return False if len(value) != 2: return False if not isinstance( key[0], ScalarNode ) or key[0].tag != 'tag:yaml.org,2002:str' or key[0].value != 'key': return False if not isinstance(value[0], ScalarNode) or value[ 0].tag != 'tag:yaml.org,2002:str' or value[0].value != 'value': return False return (simplify_mappings(key[1]), simplify_mappings(value[1])) def to_map(values): map = [] for value in values: if not isinstance(value, MappingNode): return False if value.tag != 'tag:yaml.org,2002:map': return False kv = to_key_value(value.value) if not kv: return False map.append(kv) return map if isinstance(node, SequenceNode): map = to_map(node.value) if map: node = MappingNode( tag="%s%s" % (YAML_TAG_REWRITE_MAP, node.tag if node.tag != 'tag:yaml.org,2002:seq' else ''), value=map, start_mark=node.start_mark, end_mark=node.end_mark, comment=node.comment, anchor=node.anchor) else: node.value = [simplify_mappings(value) for value in node.value] elif isinstance(node, MappingNode): node.value = [(simplify_mappings(key), simplify_mappings(value)) for (key, value) in node.value] return node