使用 yaml.dump 时如何去掉字符串中的引号

How to get rid of quotes in strings when using yaml.dump

我正在尝试使用 ruamel.yaml 从有序字典生成 cloudformation YAML 模板。 我需要在一些字符串前加上“!Sub”前缀,这是一个 cloudtemplate 函数引用,它不会与其余字符串一起用引号引起来,例如:

Type: AWS::Glue::Job
Properties:
  Role2: !Sub 'arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}'

我开始的测试代码如下所示:

from ruamel import yaml
from collections import OrderedDict

def ordered_dict_presenter(dumper, data):
    return dumper.represent_dict(data.items())

test = OrderedDict(
    {
        "Type": "AWS::Glue::Job",
        "Properties": {
            "Name": "test_job",
            "Role": "!Sub arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}",
            "Role2": "Sub arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}",
        },
    }
)
yaml.add_representer(OrderedDict, ordered_dict_presenter)

print(yaml.dump(test, default_style=None, default_flow_style=False))

它输出这个 yaml:

Type: AWS::Glue::Job
Properties:
  Name: test_job
  Role: '!Sub arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}'
  Role2: Sub arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}

似乎当字符串以非字母字符开头时,它会被自动引用。 我尝试了自定义代表来摆脱引号,但到目前为止没有任何运气。我怎样才能输出这个?

首先你真的不应该再使用旧的 API 了,有一个新的,它允许更多的控制 关于你几年来所做的事情。

其次,你不能把一些看起来像标签的东西放在字符串中,然后 没有得到报价,在加载过程中会像标签一样加载,你可能想要 那个,但是那会产生无限数量的字符串(所有以 !) 在 YAML 中不可表示。

如果您不知道从哪里开始,可以尝试往返(加载然后转储)您需要的结果:

import sys
import ruamel.yaml

yaml_str = """\
Type: AWS::Glue::Job
Properties:
  Role2: !Sub arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}
"""

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

这给出:

Type: AWS::Glue::Job
Properties:
  Role2: !Sub arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}

这确认 ruamel.yaml 可以创建输出。现在你只需要从头开始。为此你可以 检查 data 尤其是 data['Properties']['Role2'] (如果事情不经常往返但不是必需的,意味着 你无法生成你想要的东西,但在这种情况下找出如何去做可能会更难)。

print(type(data['Properties']['Role2']))

这会打印:

Type: AWS::Glue::Job
Properties:
  Role2: !Sub arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}
<class 'ruamel.yaml.comments.TaggedScalar'>

现在你只需要了解 TaggedScalar 的工作原理(源代码在 comments.py):

import sys
import ruamel.yaml

data = {}
data['Properties'] = props = {}
props['Role2'] = ruamel.yaml.comments.TaggedScalar('arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}', style=None, tag='!Sub')

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.dump(data, sys.stdout)

给予:

Properties:
  Role2: !Sub arn:aws:iam::${AWS::AccountId}:role/${GlueServiceRole}

或者如果您确实想要引号,您可以指定 style="'"style='"'