I am trying to populate a YAML file with values from a dictionary in python.
from jinja2 import Environment, FileSystemLoader
import glob
def map_template(context,template_path,template_name,destination):
environment = Environment(loader = FileSystemLoader(template_path), trim_blocks=True, lstrip_blocks=True)
results_filename = destination
results_template = environment.get_template(template_name)
with open(results_filename, mode="w", encoding="utf-8") as results:
results.write(results_template.render(context))
print(f"... wrote {results_filename}")
The value in the context looks like
{'node' : {'value' : [{'key1':val1,'key2':"str2",'key3':val3}] } }
The wanted output YAML looks like
node:
- key1:val1
key2:"str2"
key3: val3
My current solution in my template
node:
- {{node.value[0].key1}}
{{node.value[0].key2}}
{{node.value[0].key3}}
But is there a way to dynamically explode the list using jinja2 template without having to hardcode the number of elements and their names?
One complicating factor here is that your data structure doesn't match your desired output. Rather than trying to produce YAML through a templating process, you should first generate the appropriate data structure. If you have something like:
data = {
"node": {
"value": [
{"key1": "val1", "key2": "str2", "key3": "val3"},
]
}
}
context = {"node_value": {"node": data["node"]["value"]}}
Then you could register a custom to_yaml
filter that would use the yaml
module to produce the desired output:
from jinja2 import Environment, FileSystemLoader
import yaml
def to_yaml(val):
return yaml.safe_dump(val)
data = {
"node": {
"value": [
{"key1": "val1", "key2": "str2", "key3": "val3"},
]
}
}
context = {"node_value": {"node": data["node"]["value"]}}
environment = Environment(
loader=FileSystemLoader("."), trim_blocks=True, lstrip_blocks=True
)
environment.filters["to_yaml"] = to_yaml
results_template = environment.get_template("example.j2")
with open("example.txt", mode="w", encoding="utf-8") as results:
results.write(results_template.render(context))
Given this content in example.j2
:
{{ node_value|to_yaml }}
The above code produces the following example.txt
:
node:
- key1: val1
key2: str2
key3: val3
If for some reason you can't modify your context value, you could do something like this instead in your template:
node:
{{ node.value|to_yaml }}
Which will also produce:
node:
- key1: val1
key2: str2
key3: val3
And of course you can use things like the indent
filter if you want the content shift over as in your question.