def prepare_for_dump( self, yaml_writer: Any, output_file: str = "" ) -> OutputDocTypes: """ Prepare this merged document and its writer for final rendering. This coalesces the YAML writer's settings to, in particular, distinguish between YAML and JSON. It will also force demarcation of every String key and value within the document when the output will be JSON. Parameters: 1. yaml_writer (ruamel.yaml.YAML) The YAML document writer Returns: (OutputDocTypes) One of: * OutputDocTypes.JSON: The document and yaml_writer are JSON format. * OutputDocTypes.YAML: The document and yaml_writer are YAML format. """ # Check whether the user is forcing an output format doc_format = self.config.get_document_format() if doc_format is OutputDocTypes.AUTO: # Identify by file-extension, if it indicates a known type file_extension = (Path(output_file).suffix.lower() if output_file else "") if file_extension in [".json", ".yaml", ".yml"]: is_flow = file_extension == ".json" else: # Check whether the document root is in flow or block format is_flow = True if hasattr(self.data, "fa"): is_flow = self.data.fa.flow_style() else: is_flow = doc_format is OutputDocTypes.JSON if is_flow: # Dump the document as true JSON and reload it; this automatically # exlodes all aliases. xfer_buffer = StringIO() json.dump(Parsers.jsonify_yaml_data(self.data), xfer_buffer) xfer_buffer.seek(0) self.data = yaml_writer.load(xfer_buffer) # Ensure the writer doesn't emit a YAML Start-of-Document marker yaml_writer.explicit_start = False else: # Ensure block style output Parsers.set_flow_style(self.data, False) # When writing YAML, ensure the document start mark is emitted yaml_writer.explicit_start = True return OutputDocTypes.JSON if is_flow else OutputDocTypes.YAML
def set_flow_style(cls, *args): """Relay function call to static method.""" if not cls.depwarn_printed: cls.depwarn_printed = True print(Merger.DEPRECATION_WARNING, file=sys.stderr) Parsers.set_flow_style(*args)
def merge_with(self, rhs: Any) -> None: """ Merge this document with another. Parameters: 1. rhs (Any) The document to merge into this one. Returns: N/A Raises: - `MergeException` when a clean merge is impossible. """ # Do nothing when RHS is None (empty document) if rhs is None: return # Remove all comments (no sensible way to merge them) Parsers.delete_all_comments(rhs) # When LHS is None (empty document), just dump all of RHS into it, # honoring any --mergeat|-m location as best as possible. insert_at = self.config.get_insertion_point() if self.data is None: self.logger.debug( "Replacing None data with:", prefix="Merger::merge_with: ", data=rhs, data_header=" *****") self.data = Nodes.build_next_node(insert_at, 0, rhs) self.logger.debug( "Merged document is now:", prefix="Merger::merge_with: ", data=self.data, footer=" ***** ***** *****") if isinstance(rhs, (dict, list, CommentedSet, set)): # Only Scalar values need further processing return # Resolve any anchor conflicts self._resolve_anchor_conflicts(rhs) # Prepare the merge rules self.config.prepare(rhs) # Merge into each insertion point merge_performed = False lhs_proc = Processor(self.logger, self.data) for node_coord in self._get_merge_target_nodes( insert_at, lhs_proc, rhs ): target_node = node_coord.node Parsers.set_flow_style( rhs, (target_node.fa.flow_style() if hasattr(target_node, "fa") else None)) if isinstance(rhs, CommentedMap): # The RHS document root is a dict merge_performed = self._insert_dict( insert_at, target_node, rhs) elif isinstance(rhs, CommentedSeq): # The RHS document root is a list merge_performed = self._insert_list( insert_at, target_node, rhs) elif isinstance(rhs, CommentedSet): # The RHS document is a set merge_performed = self._insert_set( insert_at, target_node, rhs) else: # The RHS document root is a Scalar value merge_performed = self._insert_scalar( insert_at, target_node, lhs_proc, rhs) self.logger.debug( "Completed merge operation, resulting in document:", prefix="Merger::merge_with: ", data=self.data) if not merge_performed: raise MergeException( "A merge was not performed. Ensure your target path matches" " at least one node in the left document(s).", insert_at)
def merge_with(self, rhs: Any) -> None: """ Merge this document with another. Parameters: 1. rhs (Any) The document to merge into this one. Returns: N/A Raises: - `MergeException` when a clean merge is impossible. """ # Do nothing when RHS is None (empty document) if rhs is None: return # Remove all comments (no sensible way to merge them) Parsers.delete_all_comments(rhs) # When LHS is None (empty document), just dump all of RHS into it, # honoring any --mergeat|-m location as best as possible. insert_at = self.config.get_insertion_point() if self.data is None: self.logger.debug("Replacing None data with:", prefix="Merger::merge_with: ", data=rhs, data_header=" *****") self.data = Nodes.build_next_node(insert_at, 0, rhs) self.logger.debug("Merged document is now:", prefix="Merger::merge_with: ", data=self.data, footer=" ***** ***** *****") if isinstance(rhs, (dict, list)): # Only Scalar values need further processing return # Resolve any anchor conflicts self._resolve_anchor_conflicts(rhs) # Prepare the merge rules self.config.prepare(rhs) # Identify a reasonable default should a DOM need to be built up to # receive the RHS data. default_val = rhs if isinstance(rhs, CommentedMap): default_val = {} elif isinstance(rhs, CommentedSeq): default_val = [] # Loop through all insertion points and the elements in RHS merge_performed = False nodes: List[NodeCoords] = [] lhs_proc = Processor(self.logger, self.data) for node_coord in lhs_proc.get_nodes(insert_at, default_value=default_val): nodes.append(node_coord) for node_coord in nodes: target_node = (node_coord.node if isinstance( node_coord.node, (CommentedMap, CommentedSeq)) else node_coord.parent) Parsers.set_flow_style(rhs, (target_node.fa.flow_style() if hasattr( target_node, "fa") else None)) if isinstance(rhs, CommentedMap): # The RHS document root is a map if isinstance(target_node, CommentedSeq): # But the destination is a list self._merge_lists(target_node, CommentedSeq([rhs]), insert_at) else: self._merge_dicts(target_node, rhs, insert_at) # Synchronize YAML Tags self.logger.debug( "Merger::merge_with: Setting LHS tag from {} to {}.". format(target_node.tag.value, rhs.tag.value)) target_node.yaml_set_tag(rhs.tag.value) merge_performed = True elif isinstance(rhs, CommentedSeq): # The RHS document root is a list self._merge_lists(target_node, rhs, insert_at) merge_performed = True # Synchronize any YAML Tag self.logger.debug( "Merger::merge_with: Setting LHS tag from {} to {}.". format(target_node.tag.value, rhs.tag.value)) target_node.yaml_set_tag(rhs.tag.value) else: # The RHS document root is a Scalar value target_node = node_coord.node if isinstance(target_node, CommentedSeq): Nodes.append_list_element(target_node, rhs) merge_performed = True elif isinstance(target_node, CommentedMap): raise MergeException( "Impossible to add Scalar value, {}, to a Hash without" " a key. Change the value to a 'key: value' pair, a" " '{{key: value}}' Hash, or change the merge target to" " an Array or other Scalar value.".format(rhs), insert_at) else: lhs_proc.set_value(insert_at, rhs) merge_performed = True self.logger.debug("Completed merge operation, resulting in document:", prefix="Merger::merge_with: ", data=self.data) if not merge_performed: raise MergeException( "A merge was not performed. Ensure your target path matches" " at least one node in the left document(s).", insert_at)