Example #1
0
    def test_debug_noisy(self, capsys):
        args = SimpleNamespace(verbose=False, quiet=False, debug=True)
        logger = ConsolePrinter(args)
        anchoredkey = PlainScalarString("TestKey", anchor="KeyAnchor")
        anchoredval = PlainScalarString("TestVal", anchor="Anchor")

        logger.debug(anchoredval)
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  TestVal; &Anchor",
        ]) + "\n" == console.out

        logger.debug(["test", anchoredval])
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  [0]=test",
            "DEBUG:  [1]=TestVal; &Anchor",
        ]) + "\n" == console.out

        logger.debug({"ichi": 1, anchoredkey: anchoredval})
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  [ichi]=>1",
            "DEBUG:  [TestKey; &KeyAnchor]=>TestVal; &Anchor",
        ]) + "\n" == console.out
Example #2
0
    def wrap_type(value: Any) -> Any:
        """
        Wrap a value in one of the ruamel.yaml wrapper types.

        Parameters:
        1. value (Any) The value to wrap.

        Returns: (Any) The wrapped value or the original value when a better
            wrapper could not be identified.

        Raises:  N/A
        """
        wrapped_value = value
        ast_value = Nodes.typed_value(value)
        typ = type(ast_value)
        if typ is list:
            wrapped_value = CommentedSeq(value)
        elif typ is dict:
            wrapped_value = CommentedMap(value)
        elif typ is str:
            wrapped_value = PlainScalarString(value)
        elif typ is int:
            wrapped_value = ScalarInt(value)
        elif typ is float:
            wrapped_value = Nodes.make_float_node(ast_value)
        elif typ is bool:
            wrapped_value = ScalarBoolean(bool(value))

        return wrapped_value
Example #3
0
 def test_search_anchor(self):
     anchor_value = "anchor_name"
     node = PlainScalarString("anchored value", anchor=anchor_value)
     terms = SearchTerms(False, PathSearchMethods.CONTAINS, ".", "name")
     seen_anchors = []
     search_anchors = True
     include_aliases = True
     assert search_anchor(
         node,
         terms,
         seen_anchors,
         search_anchors=search_anchors,
         include_aliases=include_aliases) == AnchorMatches.MATCH
Example #4
0
class Test_enums_YAMLValueFormats():
    """Tests for the YAMLValueFormats enumeration."""
    def test_get_names(self):
        assert YAMLValueFormats.get_names() == [
            "BARE",
            "BOOLEAN",
            "DEFAULT",
            "DQUOTE",
            "FLOAT",
            "FOLDED",
            "INT",
            "LITERAL",
            "SQUOTE",
        ]

    @pytest.mark.parametrize("input,output", [
        ("BARE", YAMLValueFormats.BARE),
        ("BOOLEAN", YAMLValueFormats.BOOLEAN),
        ("DEFAULT", YAMLValueFormats.DEFAULT),
        ("DQUOTE", YAMLValueFormats.DQUOTE),
        ("FLOAT", YAMLValueFormats.FLOAT),
        ("FOLDED", YAMLValueFormats.FOLDED),
        ("INT", YAMLValueFormats.INT),
        ("LITERAL", YAMLValueFormats.LITERAL),
        ("SQUOTE", YAMLValueFormats.SQUOTE),
    ])
    def test_from_str(self, input, output):
        assert output == YAMLValueFormats.from_str(input)

    def test_from_str_nameerror(self):
        with pytest.raises(NameError):
            YAMLValueFormats.from_str("NO SUCH NAME")

    @pytest.mark.parametrize("input,output", [
        (FoldedScalarString(""), YAMLValueFormats.FOLDED),
        (LiteralScalarString(""), YAMLValueFormats.LITERAL),
        (DoubleQuotedScalarString(''), YAMLValueFormats.DQUOTE),
        (SingleQuotedScalarString(""), YAMLValueFormats.SQUOTE),
        (PlainScalarString(""), YAMLValueFormats.BARE),
        (ScalarBoolean(False), YAMLValueFormats.BOOLEAN),
        (ScalarFloat(1.01), YAMLValueFormats.FLOAT),
        (ScalarInt(10), YAMLValueFormats.INT),
        (None, YAMLValueFormats.DEFAULT),
    ])
    def test_from_node(self, input, output):
        assert output == YAMLValueFormats.from_node(input)
Example #5
0
def base64_encode_secrets(content: str) -> str:
    """
    Base64 encode a Kubernetes Secret yaml file

    :return str: The readable version of the yaml file.
    """

    yaml = YAML()
    secrets = yaml.load(content)

    data = secrets["data"]
    for key, value in data.items():
        if value is not None:
            value = base64.b64encode(value.encode("utf-8")).decode("utf-8")
            data[key] = PlainScalarString(value)

    stream = StringIO()
    yaml.dump(secrets, stream)
    return stream.getvalue().rstrip() + "\n"
Example #6
0
def base64_encode_secrets(content: str) -> str:
    """
    Base64 encode a Kubernetes Secret yaml file

    :return str: The readable version of the yaml file.
    """

    ruamel_yaml = YAML()
    secrets = ruamel_yaml.load(content)

    data = secrets["data"]
    for key, value in data.items():
        if value is not None:
            value = normalize_line_endings(value)
            value = base64encode(value)
            data[key] = PlainScalarString(value)

    stream = StringIO()
    ruamel_yaml.dump(secrets, stream)
    return stream.getvalue().rstrip() + "\n"
Example #7
0
def replace_quoted_strings(data: Any, options: QuotedStringOptions) -> Any:
    quote_cast = (
        SingleQuotedScalarString
        if options.quote_type == SINGLE
        else DoubleQuotedScalarString
    )
    patterns = options.extra_required + options.extra_allowed
    # it won't work with items() or iterating through it like list
    if isinstance(data, CommentedMap):
        for key in data.keys():
            data[key] = replace_quoted_strings(data[key], options)
    elif isinstance(data, CommentedSeq):
        for indx in range(len(data)):
            data[indx] = replace_quoted_strings(data[indx], options)
    elif isinstance(data, str):
        if (
            options.required == ONLY_WHEN_NEEDED
            and isinstance(data, (SingleQuotedScalarString, DoubleQuotedScalarString))
            and not _quotes_are_needed(data)
            and all(pattern.search(data) is None for pattern in patterns)
        ):
            return PlainScalarString(data)
        elif (
            options.required == TRUE
            or _quotes_are_needed(data)
            or any(
                pattern.search(data) is not None for pattern in options.extra_required
            )
        ) and not isinstance(
            data, (SingleQuotedScalarString, DoubleQuotedScalarString)
        ):
            return quote_cast(data)
        elif options.quote_type == SINGLE and isinstance(
            data, DoubleQuotedScalarString
        ):
            return SingleQuotedScalarString(data)
        elif options.quote_type == DOUBLE and isinstance(
            data, SingleQuotedScalarString
        ):
            return DoubleQuotedScalarString(data)
    return data
    def test_debug_noisy(self, capsys):
        args = SimpleNamespace(verbose=False, quiet=False, debug=True)
        logger = ConsolePrinter(args)
        anchoredkey = PlainScalarString("TestKey", anchor="KeyAnchor")
        anchoredval = PlainScalarString("TestVal", anchor="Anchor")
        foldedstr = "123456789 123456789 123456789"
        foldedstrfolds = [10, 20]
        foldedval = FoldedScalarString(foldedstr)
        foldedval.fold_pos = foldedstrfolds

        logger.debug(anchoredval)
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  (&Anchor)TestVal",
        ]) + "\n" == console.out

        logger.debug(["test", anchoredval])
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  [0]test<class 'str'>",
            "DEBUG:  [1](&Anchor)TestVal<class 'ruamel.yaml.scalarstring.PlainScalarString'>",
        ]) + "\n" == console.out

        logger.debug({"ichi": 1, anchoredkey: anchoredval})
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  [ichi]1<class 'int'>",
            "DEBUG:  [TestKey](&KeyAnchor,&Anchor)TestVal<class 'ruamel.yaml.scalarstring.PlainScalarString'>",
        ]) + "\n" == console.out

        logger.debug({"ichi": 1, anchoredkey: "non-anchored value"})
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  [ichi]1<class 'int'>",
            "DEBUG:  [TestKey](&KeyAnchor,_)non-anchored value<class 'str'>",
        ]) + "\n" == console.out

        logger.debug({"ichi": 1, "non-anchored-key": anchoredval})
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  [ichi]1<class 'int'>",
            "DEBUG:  [non-anchored-key](_,&Anchor)TestVal<class 'ruamel.yaml.scalarstring.PlainScalarString'>",
        ]) + "\n" == console.out

        tagged_value = "value"
        tagged_value_node = TaggedScalar(tagged_value, tag="!tag")
        tagged_sequence = CommentedSeq(["a", "b"])
        tagged_sequence.yaml_set_tag("!raz")
        selfref_value = "self_referring"
        selfref_value_node = TaggedScalar(selfref_value, tag="!self_referring")
        logger.debug(
            "test_wrappers_consoleprinter:",
            prefix="test_debug_noisy:  ",
            header="--- HEADER ---",
            footer="=== FOOTER ===",
            data_header="+++ DATA HEADER +++",
            data_footer="::: DATA FOOTER :::",
            data=CommentedMap({
                "key": "value",
                "tagged": tagged_value_node,
                tagged_value_node: "untagged value",
                selfref_value_node: selfref_value_node,
                "array": ["ichi", "ni", "san"],
                "tagged_array": tagged_sequence,
                "aoh": [{"id": 1},{"id": 2},{"id": 3}],
                "aoa": [[True, True], [True, False], [False, True]],
                "dod": {"a": {"b": {"c": "d"}}},
                "set": CommentedSet(["one", "two"]),
            })
        )
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  test_debug_noisy:  --- HEADER ---",
            "DEBUG:  test_debug_noisy:  test_wrappers_consoleprinter:",
            "DEBUG:  test_debug_noisy:  +++ DATA HEADER +++",
            "DEBUG:  test_debug_noisy:  [key]value<class 'str'>",
            "DEBUG:  test_debug_noisy:  [tagged]<_,!tag>value<class 'ruamel.yaml.comments.TaggedScalar'>(<class 'str'>)",
            "DEBUG:  test_debug_noisy:  [value]<!tag,_>untagged value<class 'str'>",
            "DEBUG:  test_debug_noisy:  [self_referring]<!self_referring,!self_referring>self_referring<class 'ruamel.yaml.comments.TaggedScalar'>(<class 'str'>)",
            "DEBUG:  test_debug_noisy:  [array][0]ichi<class 'str'>",
            "DEBUG:  test_debug_noisy:  [array][1]ni<class 'str'>",
            "DEBUG:  test_debug_noisy:  [array][2]san<class 'str'>",
            "DEBUG:  test_debug_noisy:  [tagged_array]<_,!raz>[0]a<class 'str'>",
            "DEBUG:  test_debug_noisy:  [tagged_array]<_,!raz>[1]b<class 'str'>",
            "DEBUG:  test_debug_noisy:  [aoh][0][id]1<class 'int'>",
            "DEBUG:  test_debug_noisy:  [aoh][1][id]2<class 'int'>",
            "DEBUG:  test_debug_noisy:  [aoh][2][id]3<class 'int'>",
            "DEBUG:  test_debug_noisy:  [aoa][0][0]True<class 'bool'>",
            "DEBUG:  test_debug_noisy:  [aoa][0][1]True<class 'bool'>",
            "DEBUG:  test_debug_noisy:  [aoa][1][0]True<class 'bool'>",
            "DEBUG:  test_debug_noisy:  [aoa][1][1]False<class 'bool'>",
            "DEBUG:  test_debug_noisy:  [aoa][2][0]False<class 'bool'>",
            "DEBUG:  test_debug_noisy:  [aoa][2][1]True<class 'bool'>",
            "DEBUG:  test_debug_noisy:  [dod][a][b][c]d<class 'str'>",
            "DEBUG:  test_debug_noisy:  [set]{one}<class 'str'>",
            "DEBUG:  test_debug_noisy:  [set]{two}<class 'str'>",
            "DEBUG:  test_debug_noisy:  ::: DATA FOOTER :::",
            "DEBUG:  test_debug_noisy:  === FOOTER ===",
        ]) + "\n" == console.out

        logger.debug(tagged_value_node)
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  <!tag>value<class 'ruamel.yaml.comments.TaggedScalar'>(<class 'str'>)",
        ])

        logger.debug(tagged_sequence)
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  [tagged_array]<!raz>[0]a<class 'str'>",
            "DEBUG:  [tagged_array]<!raz>[1]b<class 'str'>",
        ])

        nc = NodeCoords(
            "value",
            dict(key="value"),
            "key",
            YAMLPath("doc_root.key"),
            [   (dict(doc_root=dict(key="value")), "doc_root"),
                (dict(key="value"), "key")],
            (PathSegmentTypes.KEY, "key")
        )
        logger.debug(
            "A node coordinate:", prefix="test_debug_noisy:  ", data=nc)
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  test_debug_noisy:  A node coordinate:",
            "DEBUG:  test_debug_noisy:  (path)doc_root.key",
            "DEBUG:  test_debug_noisy:  (segment)[0]PathSegmentTypes.KEY<enum 'PathSegmentTypes'>",
            "DEBUG:  test_debug_noisy:  (segment)[1]key<class 'str'>",
            "DEBUG:  test_debug_noisy:  (node)value",
            "DEBUG:  test_debug_noisy:  (parent)[key]value<class 'str'>",
            "DEBUG:  test_debug_noisy:  (parentref)key",
            "DEBUG:  test_debug_noisy:  (ancestry)[0][0][doc_root][key]value<class 'str'>",
            "DEBUG:  test_debug_noisy:  (ancestry)[0][1]doc_root<class 'str'>",
            "DEBUG:  test_debug_noisy:  (ancestry)[1][0][key]value<class 'str'>",
            "DEBUG:  test_debug_noisy:  (ancestry)[1][1]key<class 'str'>",
        ]) + "\n" == console.out

        logger.debug(foldedval)
        console = capsys.readouterr()
        assert "\n".join([
            "DEBUG:  {}<class 'ruamel.yaml.scalarstring.FoldedScalarString'>,folded@{}".format(foldedstr, foldedstrfolds)
        ])
Example #9
0
    def make_new_node(source_node: Any, value: Any,
                      value_format: YAMLValueFormats, **kwargs) -> Any:
        """
        Create a new data node based on a sample node.

        This is achieved by effectively duplicaing the type and anchor of the
        node but giving it a different value.

        Parameters:
        1. source_node (Any) The node from which to copy type
        2. value (Any) The value to assign to the new node
        3. value_format (YAMLValueFormats) The YAML presentation format to
           apply to value when it is dumped

        Keyword Arguments:
        * tag (str) Custom data-type tag to apply to this node

        Returns: (Any) The new node

        Raises:
        - `NameError` when value_format is invalid
        - `ValueError' when the new value is not numeric and value_format
        requires it to be so
        """
        new_node = None
        new_type = type(source_node)
        new_value = value
        valform = YAMLValueFormats.DEFAULT

        if isinstance(value_format, YAMLValueFormats):
            valform = value_format
        else:
            strform = str(value_format)
            try:
                valform = YAMLValueFormats.from_str(strform)
            except NameError as wrap_ex:
                raise NameError(
                    "Unknown YAML Value Format:  {}".format(strform) +
                    ".  Please specify one of:  " + ", ".join(
                        [l.lower()
                         for l in YAMLValueFormats.get_names()])) from wrap_ex

        if valform == YAMLValueFormats.BARE:
            new_type = PlainScalarString
            new_value = str(value)
        elif valform == YAMLValueFormats.DQUOTE:
            new_type = DoubleQuotedScalarString
            new_value = str(value)
        elif valform == YAMLValueFormats.SQUOTE:
            new_type = SingleQuotedScalarString
            new_value = str(value)
        elif valform == YAMLValueFormats.FOLDED:
            new_type = FoldedScalarString
            new_value = str(value)
            preserve_folds = []

            # Scan all except the very last character because if that last
            # character is a newline, ruamel.yaml will crash when told to fold
            # there.
            for index, fold_char in enumerate(new_value[:-1]):
                if fold_char == "\n":
                    preserve_folds.append(index)

            # Replace all except the very last character
            new_value = new_value[:-1].replace("\n", " ") + new_value[-1]

            if hasattr(source_node, "anchor") and source_node.anchor.value:
                new_node = new_type(new_value, anchor=source_node.anchor.value)
            else:
                new_node = new_type(new_value)

            if preserve_folds:
                new_node.fold_pos = preserve_folds  # type: ignore

        elif valform == YAMLValueFormats.LITERAL:
            new_type = LiteralScalarString
            new_value = str(value)
        elif valform == YAMLValueFormats.BOOLEAN:
            new_type = ScalarBoolean
            if isinstance(value, bool):
                new_value = value
            else:
                new_value = strtobool(value)
        elif valform == YAMLValueFormats.FLOAT:
            try:
                new_value = float(value)
            except ValueError as wrap_ex:
                raise ValueError(
                    ("The requested value format is {}, but '{}' cannot be" +
                     " cast to a floating-point number.").format(
                         valform, value)) from wrap_ex

            anchor_val = None
            if hasattr(source_node, "anchor"):
                anchor_val = source_node.anchor.value
            new_node = Nodes.make_float_node(new_value, anchor_val)
        elif valform == YAMLValueFormats.INT:
            new_type = ScalarInt

            try:
                new_value = int(value)
            except ValueError as wrap_ex:
                raise ValueError(
                    ("The requested value format is {}, but '{}' cannot be" +
                     " cast to an integer number.").format(valform,
                                                           value)) from wrap_ex
        else:
            # Punt to whatever the best Scalar type may be
            try:
                wrapped_value = Nodes.wrap_type(value)
            except ValueError:
                # Value cannot be safely converted to any native type
                new_type = PlainScalarString
                wrapped_value = PlainScalarString(value)

            if Nodes.node_is_leaf(wrapped_value):
                new_type = type(wrapped_value)
            else:
                # Disallow conversions to complex types
                new_type = PlainScalarString
                wrapped_value = PlainScalarString(value)

            new_format = YAMLValueFormats.from_node(wrapped_value)
            if new_format is not YAMLValueFormats.DEFAULT:
                new_node = Nodes.make_new_node(source_node, value, new_format,
                                               **kwargs)

        if new_node is None:
            if hasattr(source_node, "anchor") and source_node.anchor.value:
                new_node = new_type(new_value, anchor=source_node.anchor.value)
            elif new_type is not type(None):
                new_node = new_type(new_value)

        # Apply a custom tag, if provided
        if "tag" in kwargs:
            new_node = Nodes.apply_yaml_tag(new_node, kwargs.pop("tag"))

        return new_node
Example #10
0
 def test_get_node_anchor(self):
     anchor_value = "anchored"
     node = PlainScalarString("value")
     node.yaml_set_anchor(anchor_value)
     assert get_node_anchor(node) == anchor_value
Example #11
0
    def test_clone_node(self):
        test_val = "test"
        assert test_val == clone_node(test_val)

        anchor_val = PlainScalarString(test_val, anchor="anchor")
        assert anchor_val == clone_node(anchor_val)