python - 解析嵌套的自定义 yaml 标签
问题描述
我有一些带有应用程序特定标签的 yaml(准确地说,来自 AWS Cloud Formation 模板),如下所示:
example_yaml = "Name: !Join [' ', ['EMR', !Ref 'Environment', !Ref 'Purpose']]"
我想解析它以便我可以这样做:
>>> print(result)
>>> {'Name': 'EMR {Environment} {Purpose}'}
>>> name = result['name'].format(
... Environment='Development',
... Purpose='ETL'
... )
>>> print(name)
>>> EMR Development ETL
目前我的代码如下所示:
import yaml
from pprint import pprint
def aws_join(loader, node):
join_args = loader.construct_yaml_seq(node)
delimiter = list(join_args)[0]
joinables = list(join_args)[1]
join_result = delimiter.join(joinables)
return join_result
def aws_ref(loader, node):
value = loader.construct_scalar(node)
placeholder = '{'+value+'}'
return placeholder
yaml.add_constructor('!Join', aws_join)
yaml.add_constructor('!Ref', aws_ref)
example_yaml = "Name: !Join [' ', ['EMR', !Ref 'Environment', !Ref 'Purpose']]"
pprint(yaml.load(example_yaml))
不幸的是,这会导致错误。
...
joinables = list(join_args)[1]
IndexError: list index out of range
添加print('What I am: '+str(join_args))
到aws_join
显示我正在获得一个生成器:
What I am: <generator object SafeConstructor.construct_yaml_seq at 0x1082ece08>
这就是为什么我尝试将生成器转换为列表的原因。生成器最终会正确填充,只是没有及时让我使用它。如果我将aws_join
功能更改为这样:
def aws_join(loader, node):
join_args = loader.construct_yaml_seq(node)
return join_args
那么最终的结果是这样的:
{'Name': [' ', ['EMR', '{Environment}', '{Purpose}']]}
所以我的功能所需的部分就在那里,只是当我在我的功能中需要它们时。
解决方案
You are close, but the problem is that you are using the method
construct_yaml_seq()
. That method is actually a registered
constructor for the normal YAML sequence (the one that eventually makes
a Python list) and it calls the construct_sequence()
method to handle the
node that gets passed in, and that is what you should do as well.
As you are returning a string, which cannot deal with recursive data
structures, you don't need to use the two step creation process (first
yield
-ing, then filling out) which the construct_yaml_seq()
method
follows. But this two step creation process is why you encountered a
generator.
construct_sequence
returns a simple list, but as you want the nodes
underneath the !Join
available when you start processing, make sure
to specify the deep=True
parameter, otherwise the second list
element will be an empty list. And because construct_yaml_seq()
,
doesn't specify deep=True
, you did not get the pieces in time in
your function (otherwise you could have actually used that method).
import yaml
from pprint import pprint
def aws_join(loader, node):
join_args = loader.construct_sequence(node, deep=True)
# you can comment out next line
assert join_args == [' ', ['EMR', '{Environment}', '{Purpose}']]
delimiter = join_args[0]
joinables = join_args[1]
return delimiter.join(joinables)
def aws_ref(loader, node):
value = loader.construct_scalar(node)
placeholder = '{'+value+'}'
return placeholder
yaml.add_constructor('!Join', aws_join, Loader=yaml.SafeLoader)
yaml.add_constructor('!Ref', aws_ref, Loader=yaml.SafeLoader)
example_yaml = "Name: !Join [' ', ['EMR', !Ref 'Environment', !Ref 'Purpose']]"
pprint(yaml.safe_load(example_yaml))
which gives:
{'Name': 'EMR {Environment} {Purpose}'}
You should not use load()
, it is documented to be potentially
unsafe, and above all: it is not necessary here. Register with the
SafeLoader
and call safe_load()
推荐阅读
- apache-kafka - 如何检查卡夫卡的节流率?
- python-2.7 - 我正在尝试使用 pythons 库制作一个 Checkbox 检测代码,但它给出了一个错误(我是 python 新手)
- slider - 如何在 Slider start 中添加 setTimeOut
- botframework - 使用自定义 C# 运行时的 BotComposer 1.4 缩放功能
- python - 在 python 中删除列表项对 reversed() 的影响
- amazon-web-services - 将 Wix 博客连接到 AWS 子域
- python - 使用具有所有相同维度的其他数组根据多个条件更新数组值
- python - 根据连续时间进行计算
- github - Github Workflow - Cython 模块在相对路径上构建失败
- gradle - Gradle:如何从工件创建分布并重命名工件