Skip to content

Instantly share code, notes, and snippets.

@waylan
Last active November 12, 2020 02:44
Show Gist options
  • Save waylan/1b288be67c0d128f5e314bf034215182 to your computer and use it in GitHub Desktop.
Save waylan/1b288be67c0d128f5e314bf034215182 to your computer and use it in GitHub Desktop.
A custom YAML tag for referencing environment variables in YAML files. The content of the env var will be resolved to one of YAML's implicit types (bool, float, int, timestamp, null, value). The content of the env var is always assumed to be a Scalar node, so sequence and mappings are ignored and simply passed through as a string.
foo: !ENV FOO
bar: !ENV [BAR]
baz: !ENV [BAZ, ~]
fbb: !ENV [FOO, BAR, BAZ, ~]
# A Python clone of https://github.com/jirutka/yaml-env-tag
import os
import yaml
from typing import Any
def construct_env_tag(loader: yaml.Loader, node: yaml.Node) -> Any:
"""Assign value of ENV variable referenced at node."""
default = None
if isinstance(node, yaml.nodes.ScalarNode):
vars = [loader.construct_scalar(node)]
elif isinstance(node, yaml.nodes.SequenceNode):
child_nodes = node.value
if len(child_nodes) > 1:
# default is resvoled using YAML's (implicit) types.
default = loader.construct_object(child_nodes[-1])
child_nodes = child_nodes[:-1]
# Env Vars are resolved as string values, ignoring (implicit) types.
vars = [loader.construct_scalar(child) for child in child_nodes]
else:
raise yaml.constructor.ConstructorError(None, None,
f'expected a scalar or sequence node, but found {node.id}',
node.start_mark)
for var in vars:
if var in os.environ:
value = os.environ[var]
# Resolve value to value of type using YAML's implicit resolvers
tag = loader.resolve(yaml.nodes.ScalarNode, value, (True, False))
return loader.construct_object(yaml.nodes.ScalarNode(tag, value))
return default
yaml.add_constructor('!ENV', construct_env_tag)
if __name__ == '__main__':
with open('example.yml', 'r') as f:
data = yaml.load(f, Loader=yaml.Loader)
print(data)
@waylan
Copy link
Author

waylan commented Nov 3, 2020

This is a Python clone of the ruby lib yaml-env-tag.

See some alternative implementations at pyyaml-tags and python_yaml_environment_variables.py, each of which insert env vars in a template string.

@waylan
Copy link
Author

waylan commented Nov 12, 2020

A fully tested version of this now lives at waylan/pyyaml-env-tag and is available to install from PyPI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment