发布于2019-09-19 10:57 阅读(1229) 评论(0) 点赞(22) 收藏(3)
我有一些预处理与一些现有的.yml文件 - 但是,其中一些嵌入了Jinja模板语法:
A:
B:
- ip: 1.2.3.4
- myArray:
- {{ jinja.variable }}
- val1
- val2
我想在这个文件中读取,并添加val3
下myArray
这样:
A:
B:
- ip: 1.2.3.4
- myArray:
- {{ jinja.variable }}
- val1
- val2
- val 3
我试着手动写出jinja模板,但是他们用单引号写了: '{{ jinja.variable }}'
对于我来说,读取这样的.yml文件并修改它们的推荐方法是什么,尽管有预先存在的Jinja语法?我想向这些文件添加信息,保持其他所有相同。
我在Python 2.7+上使用PyYAML尝试了上述内容
此答案中的解决方案已使用插件机制合并到ruamel.yaml中。在这篇文章的底部有关于如何使用它的快速和脏的说明。
更新包含jinja2“code”的YAML文件有三个方面:
让我们首先通过添加jinja2变量定义和for循环以及添加一些注释(input.yaml
)来使您的示例更加真实:
# trying to update
{% set xyz = "123" }
A:
B:
- ip: 1.2.3.4
- myArray:
- {{ jinja.variable }}
- val1
- val2 # add a value after this one
{% for d in data %}
- phone: {{ d.phone }}
name: {{ d.name }}
{% endfor %}
- {{ xyz }}
# #% or ##% should not be in the file and neither <{ or <<{
以{%
#YLL 开头的行不包含YAML,因此我们将这些作为注释(假设注释在往返时保留,见下文)。由于YAML标量不能在{
没有引用的情况下开始,我们将更{{
改为<{
。这可以通过调用以下代码完成sanitize()
(它也存储使用的模式,反之在sanitize.reverse
(使用存储的模式)完成。
保存您的YAML代码(块样式等)最好使用ruamel.yaml
(免责声明:我是该软件包的作者),这样您就不必担心输入中的流式元素被破坏为块与default_flow_style=False
其他答案使用的相当粗糙的风格一样。ruamel.yaml
还保留了注释,包括最初在文件中的注释,以及那些暂时插入以“注释掉”jinja2结构的注释%{
。
结果代码:
import sys
from ruamel.yaml import YAML
yaml = YAML()
class Sanitize:
"""analyse, change and revert YAML/jinja2 mixture to/from valid YAML"""
def __init__(self):
self.accacc = None
self.accper = None
def __call__(self, s):
len = 1
for len in range(1, 10):
pat = '<' * len + '{'
if pat not in s:
self.accacc = pat
break
else:
raise NotImplementedError('could not find substitute pattern '+pat)
len = 1
for len in range(1, 10):
pat = '#' * len + '%'
if pat not in s:
self.accper = pat
break
else:
raise NotImplementedError('could not find substitute pattern '+pat)
return s.replace('{{', self.accacc).replace('{%', self.accper)
def revert(self, s):
return s.replace(self.accacc, '{{').replace(self.accper, '{%')
def update_one(file_name, out_file_name=None):
sanitize = Sanitize()
with open(file_name) as fp:
data = yaml.load(sanitize(fp.read()))
myArray = data['A']['B'][1]['myArray']
pos = myArray.index('val2')
myArray.insert(pos+1, 'val 3')
if out_file_name is None:
yaml.dump(data, sys.stdout, transform=sanitize.revert)
else:
with open(out_file_name, 'w') as fp:
yaml.dump(data, out, transform=sanitize.revert)
update_one('input.yaml')
update_one()
使用Python 2.7 打印(指定要写入文件的第二个参数):
# trying to update
{% set xyz = "123" }
A:
B:
- ip: 1.2.3.4
- myArray:
- {{ jinja.variable }}
- val1
- val2 # add a value after this one
- val 3
{% for d in data %}
- phone: {{ d.phone }}
name: {{ d.name }}
{% endfor %}
- {{ xyz }}
# #% or ##% should not be in the file and neither <{ or <<{
如果既不是#{
也不<{
在任何原始输入中,则可以使用简单的单行函数完成清理和恢复(请参阅此文章的此版本),然后您不需要该类Sanitize
您的示例缩进了一个位置(键B
)以及两个位置(序列元素),ruamel.yaml
没有对输出缩进的精确控制(我不知道任何YAML解析器)。缩进(默认为2)应用于两个YAML映射关于序列元素(测量到元素的开头,而不是短划线)。这对重新阅读YAML没有影响,也发生在其他两个回答者的输出上(没有他们指出这个变化)。
另请注意,这YAML().load()
是安全的(即不加载任意潜在的恶意对象),而yaml.load()
其他答案中使用的肯定是不安全的,它在文档中也是如此,甚至在YAML上的WikiPedia文章中也有提及。如果使用yaml.load()
,则必须检查每个输入文件,以确保没有标记的对象可能导致光盘被擦除(或更糟)。
如果您需要反复更新你的文件,并有过的Jinja2模板控制,它可能是更好的改变Jinja2的模式一次,不能回复他们,然后指定相应的block_start_string
,variable_start_string
(可能block_end_string
和variable_end_string
)的jinja2.FileSystemLoader
添加加载到jinja2.Environment
。
If the above seems to complicated then in a a virtualenv do:
pip install ruamel.yaml ruamel.yaml.jinja2
assuming you have the input.yaml
from before you can run:
import os
from ruamel.yaml import YAML
yaml = YAML(typ='jinja2')
with open('input.yaml') as fp:
data = yaml.load(fp)
myArray = data['A']['B'][1]['myArray']
pos = myArray.index('val2')
myArray.insert(pos+1, 'val 3')
with open('output.yaml', 'w') as fp:
yaml.dump(data, fp)
os.system('diff -u input.yaml output.yaml')
to get the diff
output:
--- input.yaml 2017-06-14 23:10:46.144710495 +0200
+++ output.yaml 2017-06-14 23:11:21.627742055 +0200
@@ -8,6 +8,7 @@
- {{ jinja.variable }}
- val1
- val2 # add a value after this one
+ - val 3
{% for d in data %}
- phone: {{ d.phone }}
name: {{ d.name }}
ruamel.yaml
0.15.7 implements a new plug-in mechanism and ruamel.yaml.jinja2
is a plug-in that rewraps the code in this answer transparently for the user. Currently the information for reversion is attached to the YAML()
instance, so make sure you do yaml = YAML(typ='jinja2')
for each file you process (that information could be attached to the top-level data
instance, just like the YAML comments are).
作者:黑洞官方问答小能手
链接:https://www.pythonheidong.com/blog/article/114877/1c428d15113185cd20ba/
来源:python黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!