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
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
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
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)
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"
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"
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) ])
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
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
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)