Python: Substitute Values Into YAML During Load

There’s definitely a case to be made for automatically and efficiently applying environment variables or another set of replacements into a YAML-based config or set of instructions on load. This example uses PyYAML. We’ll use Python’s built-in string templating to replace tokens like “$NAME” with values from a dictionary. It will fail, as it should, if the name is not in the given dictionary.

import string
import yaml

def load_yaml(f, context):

    def string_constructor(loader, node):

        t = string.Template(node.value)
        value = t.substitute(context)

        return value


    l = yaml.SafeLoader
    l.add_constructor('tag:yaml.org,2002:str', string_constructor)

    token_re = string.Template.pattern
    l.add_implicit_resolver('tag:yaml.org,2002:str', token_re, None)

    x = yaml.load(f, Loader=l)
    return x

y = """\
aa: bb
cc: dd $EE ff
"""

context = {
    'EE': '123',
}

d = waw.utility.load_yaml(y, context)
print(d)

Output:

{'aa': 'bb', 'cc': 'dd 123 ff'}

Python: Writing Hex Values into YAML

YAML has the ability to express hex-values, which are then decoded as numbers. However, when you want to dump a YAML document, strings will be quoted and numbers will be decimals. In order to write actual hex-values, you need to wrap your value in another type and then tell the YAML encoder how to handle it.

This is specifically possible with the ruamel YAML encoder (pypi).

An example of how to do this:

import sys

import ruamel.yaml


class HexInt(int):
    pass

def representer(dumper, data):
    return \
        ruamel.yaml.ScalarNode(
            'tag:yaml.org,2002:int',
            '0x{:04x}'.format(data))

ruamel.yaml.add_representer(HexInt, representer)

data = {
    'item1': {
        'string_value': 'some_string',
        'hex_value': HexInt(641),
    }
}

ruamel.yaml.dump(data, sys.stdout, default_flow_style=False)

Output:

item1:
  hex_value: 0x0281
  string_value: some_string

Please note that I require that my hex-values are two bytes and padded with zeroes, so the example above will print four characters (plus the prefix): 0x{:04x} . If this doesn’t work for you, change it to whatever you require.

Thanks to this post.