PyYAML转储格式

时间:2013-12-27 17:54:05

标签: python python-3.x yaml quotes pyyaml

我知道在SO上有一些关于此的问题,但我找不到我想要的东西。

我正在使用pyyaml来阅读(.load().yml文件,修改或添加密钥,然后再次编写它(.dump())。问题是我想保留转储后的文件格式,但它会改变。

例如,我修改了密钥en.test.index.few来说"Bye"而不是"Hello"

Python:

with open(path, 'r', encoding = "utf-8") as yaml_file:
    self.dict = pyyaml.load(yaml_file)

然后,更改密钥:

with open(path, 'w', encoding = "utf-8") as yaml_file:
    dump = pyyaml.dump(self.dict, default_flow_style = False, allow_unicode = True, encoding = None)
    yaml_file.write( dump )

YAML:

之前:

en:
  test:
    new: "Bye"
    index:
      few: "Hello"
  anothertest: "Something"

后:

en:
  anothertest: Something
  test:
    index:
      few: Hello
    new: Bye

有没有办法保持相同的格式?,例如qoutes和order。我是否使用了错误的工具?

我知道也许原始文件不完全正确,但我无法控制它(这是一个Ruby on Rails i18n文件)。

非常感谢。

3 个答案:

答案 0 :(得分:67)

改为使用ruamel.yaml

图书馆战斗!两个图书馆的故事

PyYAML是effectively dead并且已经有好几年了。更复杂的是,http://pyyaml.org的官方项目似乎最近被取消了。该网站托管了PyYAML问题跟踪器,文档和下载。在撰写本文时,一切都已消失。这简直就是灾难性的。欢迎来到开源的另一天。

ruamel.yamlactively maintained。与PyYAML不同,ruamel.yaml支持:

  • YAML&lt; = 1.2。 PyYAML仅支持YAML <= 1.1。这是至关重要的,因为YAML 1.2在几个边缘情况下故意breaks backward compatibility和YAML 1.1。这通常是件坏事。在这种情况下,这使YAML 1.2成为JSON的严格超集。由于YAML 1.1 是JSON的严格超集,这是一件好事。
  • 往返保存。当调用yaml.dump()转储先前调用yaml.load()所加载的字典时:
    • PyYAML天真地忽略所有输入格式 - 包括注释,排序,引用和空格。像这么多的数字垃圾一样丢弃到最近的可用位桶。
    • ruamel.yaml巧妙地尊重所有输入格式。一切。整个风格的辣酱玉米饼馅。整个文学shebang。 所有

图书馆迁移:代码之泪的踪迹

由于ruamel.yaml是PyYAML分支,因此符合PyYAML API,因此在现有应用程序中从PyYAML切换到ruamel.yaml通常就像替换所有实例一样简单:

# This imports PyYAML. Stop doing this.
import yaml

......用这个:

# This imports "ruamel.yaml". Always do this.
from ruamel import yaml

那就是它。

不需要进行任何其他更改。 yaml.load()yaml.dump()函数应该继续按预期运行 - 现在支持YAML 1.2并积极接收错误修复的额外好处。

往返保护及其能为您做什么

为了向后兼容PyYaml,默认情况下,yaml.load()yaml.dump()函数执行往返保存。为此,请明确传递:

  • Loader=ruamel.yaml.RoundTripLoader的可选yaml.load()关键字参数。
  • Dumper=ruamel.yaml.RoundTripDumper的可选yaml.dump()关键字参数。

一个善意的例子&#34;借来&#34;来自ruamel.yaml documentation

import ruamel.yaml

inp = """\
# example
name:
  # Yet another Great Duke of Hell. He's not so bad, really.
  family: TheMighty
  given: Ashtaroth
"""

code = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)
code['name']['given'] = 'Astarte'  # Oh no you didn't.

print(ruamel.yaml.dump(code, Dumper=ruamel.yaml.RoundTripDumper), end='')

已完成。评论,排序,引用和空白现在将保持不变。

TL;博士

始终使用ruamel.yaml。永远不要使用PyYAML。 ruamel.yaml生命。 PyYAML是一个腐烂的尸体,在PyPi的砾石地面腐烂。

万岁ruamel.yaml

答案 1 :(得分:2)

<强>第一

使用以下代码表示字典数据:

mapping = list(mapping.items())
    try:
        mapping = sorted(mapping)
    except TypeError:
        pass

这就是订单改变的原因

<强>第二

有关标量类型如何呈现(带双引号或不带引号)的信息在阅读时丢失(这是图书馆的主要方法)

<强>摘要

你可以根据'Dumper'创建自己的类,并重载方法'represent_mapping'来改变字典的呈现方式

为了保存有关标量的双引号的信息,你还必须根据'Loader'创建自己的类,但我担心它会影响和其他类,并且会很难做到

答案 2 :(得分:0)

在我的情况下,如果值包含"{,则我需要},否则无效。例如:

 en:
   key1: value is 1
   key2: 'value is {1}'

要执行该操作,请从模块PyYaml中的文件 representer.py 复制函数represent_str(),如果字符串包含{},则使用其他样式:< / p>

def represent_str(self, data):
    tag = None
    style = None
    # Add these two lines:
    if '{' in data or '}' in data:
        style = '"'
    try:
        data = unicode(data, 'ascii')
        tag = u'tag:yaml.org,2002:str'
    except UnicodeDecodeError:
        try:
            data = unicode(data, 'utf-8')
            tag = u'tag:yaml.org,2002:str'
        except UnicodeDecodeError:
            data = data.encode('base64')
            tag = u'tag:yaml.org,2002:binary'
            style = '|'
    return self.represent_scalar(tag, data, style=style)

在您的代码中使用它:

import yaml

def represent_str(self, data):
  ...

yaml.add_representer(str, represent_str)

在这种情况下,键和值之间没有差异,这对我来说已经足够了。如果您想要键和值的不同样式,请使用函数represent_mapping

执行相同的操作