在Python中加载与Jinja2嵌套的YAML

San*_*och 6 python jinja2 pyyaml computed-properties

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

...
var1: val1
var2: val2
var3: {{var1}}-{{var2}}.txt
...
Run Code Online (Sandbox Code Playgroud)

如果我像这样在Python中加载它:

import yaml

f = open('all.yaml')
dataMap = yaml.safe_load(f)
f.close()
print(dataMap["var3"])
Run Code Online (Sandbox Code Playgroud)

输出{{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 )
Run Code Online (Sandbox Code Playgroud)

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

小智 7

首先定义一个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)
Run Code Online (Sandbox Code Playgroud)

运行:

$ ./test.py
var1: val1
var2: val2
var3: val1-val2.txt
Run Code Online (Sandbox Code Playgroud)


Ant*_*hon 0

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

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

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

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

  2. 即使您更正要读取的第一行,---文件...也不会加载,因为字典后面{{var1}}不能跟标量-(来自-{{var2}}.txt

  3. 如果您只是{{var1}}在文件中使用,PyYAML 无法加载它,因为它将 YAML 映射加载为 Python 字典,而 Python 不允许字典使用可变键。就像你TypeError在 Python 中尝试执行以下操作时得到的结果一样:{dict(var1=None): None}

所以你至少应该将输入文件更改all.yaml为:

---
var1: val1
var2: val2
var3: '{{var1}}-{{var2}}.txt'
...
Run Code Online (Sandbox Code Playgroud)

使其加载到 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"])
Run Code Online (Sandbox Code Playgroud)

将打印您想要的内容:

val1-val2.txt
Run Code Online (Sandbox Code Playgroud)