8

我有一个 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

4 回答 4

5

首先定义一个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
于 2017-12-08T01:46:09.990 回答
1

这是一种可能的解决方案:

  1. yaml使用模块解析您的 YAML 文档
  2. 遍历 YAML 文档中的键,将每个值视为 Jinja2 模板,将 YAML 文档的键作为参数传递到该模板。

例如:

import yaml
from jinja2 import Template

with open('sample.yml') as fd:
    data = yaml.load(fd)

for k, v in data.items():
    t = Template(v)
    data[k] = t.render(**data)

print yaml.safe_dump(data, default_flow_style=False)

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

于 2015-08-12T14:44:06.450 回答
0

我不相信你可以使用:

yaml.load 

或者

yaml.safe_load 

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

于 2015-12-17T10:28:20.277 回答
0

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

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

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

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

  2. 即使您更正要读取的第一行---而不是...文件也不会加载,因为 dict{{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'
...

让它在 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
于 2015-08-12T14:21:23.330 回答