Estou tentando criar um arquivo YAML a partir de algumas entradas passadas para um modelo Jinja. Quero que certas chaves encadeadas de entrada sejam opcionais e usadas na modelagem, se presentes, mas ignoradas. No exemplo abaixo, override.source.property
pode ou não existir no arquivo de entrada e override
é uma chave de nível superior quando está presente. Existe uma maneira de recuperar opcionalmente a.certain.key
seu caminho encadeado completo por meio do modelo Jinja?
# without_override.yaml
name: blah
# with_override.yaml
name: blah
overrides:
source:
property: something
# template.yaml.jinja
name: {{ name }}
source.property: {{ overrides.source.property or "property of " + name }}
source.property3: {{ overrides.source.property | default("property of " + name) }}
{# is there a way to provide a full path and return a value if it exists?
# top level document reference?
source.property2: {{ self.get("overrides.source.property") or "property of " + name }}
#}
# renderer.py
import yaml
import sys
from jinja2 import Environment, StrictUndefined, ChainableUndefined
def render_jinja(template, context):
# jinja_env = Environment(extensions=["jinja2.ext.do"], undefined=StrictUndefined)
jinja_env = Environment(extensions=["jinja2.ext.do"], undefined=ChainableUndefined)
template_obj = jinja_env.from_string(template)
return template_obj.render(**context).strip()
if __name__ == "__main__":
with open(sys.argv[1]) as f:
config = yaml.safe_load(f.read())
with open("template.yaml.jinja") as f:
template = f.read()
print(render_jinja(template, config))
# python renderer.py with_override.yaml
# using StrictUndefined or ChainedUndefined RETURNS
name: blah
source.property: something
source.property3: something
# python renderer.py without_override.yaml
# with ChainedUndefined RETURNS
name: blah
source.property: property of blah
source.property3: property of blah
# with StrictUndefined ERRORS
jinja2.exceptions.UndefinedError: 'overrides' is undefined
Você está fazendo o que está pedindo quando usa o paramater
undefined=ChainableUndefined
. Sem esse parâmetro passado para o ambiente Jinja2, a linha abaixo simplesmente geraria uma exceção (jinja2.exceptions.UndefinedError: 'overrides' is undefined
) ao tentar acessar uma variável indefinida.Você pode até mesmo encadear vários
default()
até que uma variável seja definida ou variáveis avaliadas como falsas.Se precisar fazer algo mais complexo, você sempre pode usar o próprio Python e passar o dict processado para o renderizador do modelo. Defina os valores padrão e verifique se há um valor substituído: