Python 使用 jinja2 为嵌套结构创建动态 YAML 文件

Python creating dynamic YAML file using jinja2 for nested structures

我需要创建一个基于简单 YAML 的 YAML 文件,该文件需要根据开发人员提供的属性进行更新并包含以下 YAML 结构:

- switch: null
  title: switch
  case:
    - condition: (parameter1==='Parameter1_value1')
      execute:
        - switch:
            case:
              - condition: $(parameter2) == "Parameter2_value1"
                execute:
                  - invoke:
                      parameter3:
                        parameter3_value1: null
              - condition: $(parameter2) == "Parameter2_value2"
                execute:
                  - invoke:
                      parameter3:
                        parameter3_value2: null
    - condition: (parameter1==='Parameter1_value2')
      execute:
        - switch:
            case:
              - condition: $(parameter2) == "Parameter2_value1"
                execute:
                  - invoke:
                      parameter3:
                        parameter3_value1: null
              - condition: $(parameter2) == "Parameter2_value2"
                execute:
                  - invoke:
                      parameter3:
                        parameter3_value2: null

parameter1parameter2 都可以有多个值,因此我需要根据收到的值动态填充结构。

我尝试执行以下操作:

  1. 导入以下内容
import ruamel.yaml
from jinja2 import Template
  1. 加载基本文件-
yaml = ruamel.yaml.YAML()
data_src = yaml.load(file_name)

同时从另一个 JSON 文件接收值,一旦我有了数据,我就使用 Jinja 创建了以下内容:

parameter2_data_tmpl = Template(""" -  condition: $(parameter2) == "{{ parameter2_value }}"
                        execute:
                          - invoke:
                              parameter3: {{ parameter3_value }}
                              
            """);
           
parameter2_data = parameter2_data_tmpl.render(parameter2_value = parameter2_value, parameter3_value = parameter3_value)

这就像一个魅力,当我打印它时 - 它看起来很棒。但后来我尝试将新的 YAML 片段添加到我的结构中,方法是首先将其添加到相关数组(使用 append 方法),然后将该数组分配给原始 YAML 结构中的相关元素。

但是当我将它添加到数组时,它以不同的格式添加:

case: [' -  condition: parameter2 == \"\
          parameter2_value\"\n                        execute:\n                          -\
                                        parameter3: parameter3_value\n     \                       

就像 jinja2 正确地创建了它,但不是 YAML 语法。

为什么这不起作用?除了动态创建这些代码之外,还有其他方法吗?

渲染的结果是一个字符串:

from jinja2 import Template

parameter2_data_tmpl = Template(""" -  condition: $(parameter2) == "{{ parameter2_value }}"
                        execute:
                          - invoke:
                              parameter3: {{ parameter3_value }}
                              
            """);

parameter2_value = 'parameter2_value'
parameter3_value = 'parameter3_value'
parameter2_data = parameter2_data_tmpl.render(parameter2_value = parameter2_value, parameter3_value = parameter3_value)

print(type(parameter2_data))

这给出:

<class 'str'>

当您将该字符串添加到您使用 ruamel.yaml 加载的数据结构中的某处时,您 获取带引号的标量。

你想做的是添加一个数据结构,但是你不能从 模板,因为渲染的输出是无效的 YAML。

你可以不渲染直接创建数据结构,如果你不想 为此,您应该更改模板,以便它生成有效的 YAML 输入,加载 然后将该数据结构插入 data_src 的适当位置 (从你不完整的程序中不清楚):

import sys
import ruamel.yaml
from jinja2 import Template

parameter2_data_tmpl = Template("""\
-  condition: $(parameter2) == "{{ parameter2_value }}"
   execute:
     - invoke:
         parameter3: {{ parameter3_value }}
""");

parameter2_value = 'parameter2_value'
parameter3_value = 'parameter3_value'
parameter2_data = parameter2_data_tmpl.render(parameter2_value = parameter2_value, parameter3_value = parameter3_value)

    
yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)
new_data = yaml.load(parameter2_data)

data = yaml.load("""\
case: some value to overwrite
""")
data['case'] = new_data
yaml.dump(data, sys.stdout)

给出:

case:
  - condition: $(parameter2) == "parameter2_value"
    execute:
      - invoke:
          parameter3: parameter3_value

请注意还有一个插件ruamel.yaml.jinja2 允许你加载 生成 YAML 输出和修改值的未呈现的 Jinja2 模板。