在Python中加载与Jinja2嵌套的YAML

时间:2015-08-12 13:45:00

标签: python jinja2 pyyaml

我有一个YAML文件(all.yaml),如下所示:

...
var1: val1
var2: val2
var3: {{var1}}-{{var2}}.txt
...

如果我在Python中加载它:

import yaml

f = open('all.yaml')
dataMap = yaml.safe_load(f)
f.close()
print(dataMap["var3"])

输出为{{var1}}-{{var2}}.txt而不是val1-val2.txt

是否可以用值替换嵌套变量?

我尝试加载它:

import jinja2
templateLoader = jinja2.FileSystemLoader( searchpath="/path/to/dir" )
templateEnv = jinja2.Environment( loader=templateLoader )
TEMPLATE_FILE = "all.yaml"
template = templateEnv.get_template( TEMPLATE_FILE )

不再抛出异常,现在我陷入困境,必须研究如何继续。

4 个答案:

答案 0 :(得分:0)

我不相信你可以使用:

yaml.load 

yaml.safe_load 

在包含jinja2个变量作为值的文件上。 {{variable}}将尝试被yaml解释为dict。

答案 1 :(得分:-1)

以下是一种可能的解决方案:

  1. 使用expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token 模块
  2. 解析您的YAML文档
  3. 迭代YAML文档中的键,将每个值视为Jinja2模板,并将YAML文档的键作为参数传递给它。
  4. 例如:

    yaml

    这适用于您的特定示例,但是对于嵌套数据结构不会做任何有用的事情(事实上,它可能会爆炸)。

答案 2 :(得分:-1)

首先定义一个Undefined类并加载yaml以获取已知值。然后再次加载并使用已知值进行渲染。

#!/usr/bin/env python

import yaml
from jinja2 import Template, Undefined

str1 = '''var1: val1
var2: val2
var3: {{var1}}-{{var2}}.txt
'''

class NullUndefined(Undefined):
  def __getattr__(self, key):
    return ''

t = Template(str1, undefined=NullUndefined)
c = yaml.safe_load(t.render())

print t.render(c)

运行它:

$ ./test.py
var1: val1
var2: val2
var3: val1-val2.txt

答案 3 :(得分:-2)

YAML规范中没有替换/替换标量部分。

您要在该级别上执行的任何操作都必须在您的应用程序中完成。对我来说,对于YAML,{{var1}}只是一个嵌套映射。 {{var1}}{{var1: null}: null}的缩写。之后,-不被允许。

但是您的帖子存在多个问题:

  1. 您正在使用仅支持旧版(2005)YAML 1.1的PyYAML。因此,如果不使用明确的文档开头(...),您就不能拥有多个文档(即以---结尾),就像在YAML 1.2中一样

  2. 即使您更正了第一行来阅读---而不是...,您的文件也无法加载,因为标题{{var1}}无法跟随标量- }(来自-{{var2}}.txt

  3. 如果您只在文件中使用{{var1}},PyYAML无法加载,因为它加载YAML映射作为Python dict并且Python不允许dict的可变键。就像在尝试执行此操作时在Python中获得TypeError一样:{dict(var1=None): None}

  4. 因此,您至少应将输入文件all.yaml更改为:

    ---
    var1: val1
    var2: val2
    var3: '{{var1}}-{{var2}}.txt'
    ...
    

    将此内容加载到YAML中。

    您必须加载此文件两次:

    • 一次由PyYAML获取可用于渲染模板的值
    • 曾作为jinja2的模板

    渲染模板后,在PyYAML中再次加载(字符串)并获得所需的值。

    鉴于上面在当前目录和此程序中指定的更正all.yaml

    import yaml
    import jinja2
    
    YAML_FILE = 'all.yaml'
    with open(YAML_FILE) as fp:
        dataMap = yaml.safe_load(fp)
    
    env = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath='.'))
    template = env.get_template(YAML_FILE)
    
    data = yaml.safe_load(template.render(**dataMap))
    print(data["var3"])
    

    将打印您想要的内容:

    val1-val2.txt