怎么打印出来的!在pyaml?

时间:2017-04-17 20:38:02

标签: python python-2.7 yaml pyyaml

我有代码打印出一个像YAML一样的字典:

    import yaml
    yaml.dump(
        {
        "Properties":
             {
                 "ImageId": "!Ref AParameter"
             }
        },
        new_template,
        default_flow_style=False
    )

这会创建:

Properties:
  ImageId: '!Ref AParameter'

注意ImageId的值是如何在引号内?我想打印没有引号。我如何使用PyYAML做到这一点?

1 个答案:

答案 0 :(得分:1)

!具有特殊含义,因为它用于引入an explicit tag,因此不能出现在普通(未引用)样式标量的开头。特别是YAML 1.2规范的rule 126表示这样一个普通标量的第一个字符不能是c-indicator,这就是!

这样的标量必须引用(单个或双重)PyYAML自动执行,或者以文字或折叠方式放置。

您可以将没有引号的有效YAML转储到文字块样式标量:

Properties:
  ImageId: |
    !Ref AParameter

如果没有支持性编程,PyYAML就无法做到这一点。您可以使用ruamel.yaml执行此操作(免责声明:我是该程序包的作者),将值设为PreservedScalarString实例:ruamel.yaml.scalarstring.PreservedScalarString("!Ref AParameter")

您当然可以使用!Ref标记定义转储的类,但标记上下文会强制标量AParameter周围的引号:

import sys
import yaml

class Ref(str):
    @staticmethod
    def yaml_dumper(dumper, data):
        return dumper.represent_scalar('!Ref', u'{}'.format(data), style=None)

yaml.add_representer(Ref, Ref.yaml_dumper)


yaml.dump(
    {
        "Properties":
        {
            "ImageId": Ref("AParameter"),
        }
    },
    sys.stdout,
    default_flow_style=False,
)

给出:

Properties:
  ImageId: !Ref 'AParameter'

虽然可以使用适当的构造函数加载!Ref Aparameter (例如,这里只是为了安全起见而添加引号)。

如果您还想要取消这些引号,您可以例如使用ruamel.yaml,为您的节点定义一个特殊样式'x'并为其提供发射处理:

from ruamel import yaml

class Ref(str):
    @staticmethod
    def yaml_dumper(dumper, data):
        return dumper.represent_scalar('!Ref', u'{}'.format(data), style='x')

    @staticmethod
    def yaml_constructor(loader, node):
        value = loader.construct_scalar(node)
        return Ref(value)

yaml.add_representer(Ref, Ref.yaml_dumper)
yaml.add_constructor('!Ref', Ref.yaml_constructor,
                     constructor=yaml.constructor.SafeConstructor)

def choose_scalar_style(self):
    if self.event.style == 'x':
        return ''
    return self.org_choose_scalar_style()

yaml.emitter.Emitter.org_choose_scalar_style = yaml.emitter.Emitter.choose_scalar_style
yaml.emitter.Emitter.choose_scalar_style = choose_scalar_style

data =  {
    "Properties":
    {
        "ImageId": Ref("AParameter"),
    }
}

ys = yaml.dump(data, default_flow_style=False)

print(ys)
data_out = yaml.safe_load(ys)
assert data_out == data

以上内容不会在断言上引发错误,因此数据往返和打印输出完全符合您的要求AFAICT:

Properties:
  ImageId: !Ref AParameter