Ejemplo n.º 1
0
 def test_tagless_value_syntax_error(self):
     assert "[abc" == Nodes.tagless_value("[abc")
Ejemplo n.º 2
0
    def _merge_arrays_of_hashes(
        self, lhs: CommentedSeq, rhs: CommentedSeq, path: YAMLPath,
        node_coord: NodeCoords
    ) -> CommentedSeq:
        """
        Merge two Arrays-of-Hashes.

        This is a deep merge operation.  Each dict is treated as a record with
        an identity key.  RHS records are merged with LHS records for which the
        identity key matches.  As such, an identity key is required in both LHS
        and RHS records.  This key is configurable.  When there is no LHS match
        for an RHS key, the RHS record is appended to the LHS list.

        Parameters:
        1. lhs (CommentedSeq) The merge target.
        2. rhs (CommentedSeq) The merge source.
        3. path (YAMLPath) Location within the DOM where this merge is taking
           place.
        4. node_coord (NodeCoords) The RHS root node, its parent, and reference
           within its parent; used for config lookups.

        Returns:  (CommentedSeq) The merged result.

        Raises:
        - `MergeException` when a clean merge is impossible.
        """
        if not isinstance(lhs, CommentedSeq):
            raise MergeException(
                "Impossible to add Array-of-Hash data to non-Array"
                " destination."
                , path)

        self.logger.debug(
            "Merging {} Hash(es) at {}.".format(len(rhs), path),
            prefix="Merger::_merge_arrays_of_hashes:  ", data=rhs)

        id_key: str = ""
        if len(rhs) > 0 and isinstance(rhs[0], CommentedMap):
            id_key = self.config.aoh_merge_key(
                NodeCoords(rhs[0], rhs, 0), rhs[0])
            self.logger.debug(
                "Merger::_merge_arrays_of_hashes:  RHS AoH yielded id_key:"
                "  {}.".format(id_key))

        merge_mode = self.config.aoh_merge_mode(node_coord)
        for idx, ele in enumerate(rhs):
            path_next = path + "[{}]".format(idx)
            self.logger.debug(
                "Processing element #{} at {}.".format(idx, path_next),
                prefix="Merger::_merge_arrays_of_hashes:  ", data=ele)

            if merge_mode is AoHMergeOpts.DEEP:
                if id_key in ele:
                    id_val = Nodes.tagless_value(ele[id_key])
                else:
                    raise MergeException(
                        "Mandatory identity key, {}, not present in Hash with"
                        " keys:  {}."
                        .format(id_key, ", ".join(ele.keys()))
                        , path_next
                    )

                merged_hash = False
                for lhs_hash in (
                    lhs_hash for lhs_hash in lhs
                    if isinstance(lhs_hash, CommentedMap)
                    and id_key in lhs_hash
                    and Nodes.tagless_value(lhs_hash[id_key]) == id_val
                ):
                    self._merge_dicts(lhs_hash, ele, path_next)
                    merged_hash = True

                    # Synchronize YAML Tags
                    lhs_hash.yaml_set_tag(ele.tag.value)
                    break
                if not merged_hash:
                    Nodes.append_list_element(lhs, ele,
                        ele.anchor.value if hasattr(ele, "anchor") else None)
            elif merge_mode is AoHMergeOpts.UNIQUE:
                if ele not in lhs:
                    Nodes.append_list_element(
                        lhs, ele,
                        ele.anchor.value if hasattr(ele, "anchor") else None)
            else:
                Nodes.append_list_element(lhs, ele,
                    ele.anchor.value if hasattr(ele, "anchor") else None)
        return lhs