PyYAML转储格式

nic*_*elo 37 python quotes yaml pyyaml python-3.x

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

我正在使用pyyaml来读取(.load()).yml文件,修改或添加一个键,然后.dump()再次写入它.问题是我想在转储后保留文件格式,但它会改变.

例如,我编辑键en.test.index.few"Bye",而不是"Hello"

蟒蛇:

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

然后,更改密钥:

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 )
Run Code Online (Sandbox Code Playgroud)

YAML:

之前:

en:
  test:
    new: "Bye"
    index:
      few: "Hello"
  anothertest: "Something"
Run Code Online (Sandbox Code Playgroud)

后:

en:
  anothertest: Something
  test:
    index:
      few: Hello
    new: Bye
Run Code Online (Sandbox Code Playgroud)

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

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

非常感谢你.

Cec*_*rry 76

ruamel.yaml改用.

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

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

ruamel.yaml积极维护.与PyYAML不同,ruamel.yaml支持:

  • YAML <= 1.2.PyYAML仅支持YAML <= 1.1.这一点至关重要,因为YAML 1.2 在几个边缘情况下故意破坏了与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
Run Code Online (Sandbox Code Playgroud)

...有了这个:

# This imports "ruamel.yaml". Always do this.
from ruamel import yaml
Run Code Online (Sandbox Code Playgroud)

而已.

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

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

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

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

一个从ruamel.yaml文档中 "借用"的例子:

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='')
Run Code Online (Sandbox Code Playgroud)

它完成了.现在将完整保留注释,排序,引用和空白.

TL;博士

一直用ruamel.yaml.永远不要使用PyYAML.ruamel.yaml住.PyYAML是一个腐烂的尸体,在PyPi的砾石地面腐烂.

万岁ruamel.yaml.

  • PyYAML现在有了新的维护者,最近发布了v4.1.答案已经过时,愚蠢的内容如"PyYAML是腐烂的尸体腐烂......"应该被删除. (25认同)
  • 3.x到4.x是一个主要的版本号凹凸,因此应该预期向后的incompat更改.我不否认PyYAML维护人员有问题和政治,但这个答案中使用的语言有点过分.它看起来像ruamel.yaml或宣传广告. (6认同)
  • 我必须说这是一个很好的答案.我目前没有开发使用PyYAML的项目,但是当我有空闲时间并且接受答案时,我肯定会尝试"ruamel.yaml".谢谢! (2认同)
  • @sjmh与ruamel.yaml 0.11.12开始,你可以在加载过程中指定`preserve_quotes = TRUE`,这将包裹装载所需倾倒信息的字符串.另请参阅[这个答案](http://stackoverflow.com/a/38582476/1307905) (2认同)
  • @wim aaaand PyYAML 开发再次陷入停滞,5 个月以来没有任何有意义的变化。4.1 版本 [中断](https://github.com/TankerHQ/tsrc/commit/f7fb55a5c540856560106b9e13ce3a6c347979a5) [很多](https://github.com/heilaaks/snippy/commit/d81e82e1113daca6575f4e891397e480 e69d6249) [项目](https:// /github.com/fecgov/openFEC/issues/3280),而我们目前使用的是 4.2b4,这非常尴尬。它获得适当发布的希望渺茫,而且对于一开始没有选择鲁梅尔感到非常遗憾。 (2认同)
  • 还死了 永远不要相信一个发行版,而只是一种发行版。ruamel.yaml万岁 (2认同)
  • 从Python环境中的可用性的角度来看,恐怕非常缺乏“新” PyYAML。当他们“承认学习Python”时,一些“维护者”正在修补。而且他们像Python一样强烈地反对明显的请求,例如保留字典顺序。对于这样一个相关的项目真是可惜。 (2认同)
  • 该答案应予以纠正。它立即以错误的语句开始。也许它们在编写时是正确的,但事实不再如此。PyYaml尚未终止,网站已启动。在撰写此评论时,PyYaml看上去还活着而且很踢。查看最新版本:-2019-07-30:PyYAML 5.1.2已发布。-2018-06-06:PyYAML 5.1.1已发布。-2019-03-13:发布了LibYAML 0.2.2和PyYAML 5.1。-2018-07-05:PyYAML 3.13发布。-2018-06-24:LibYAML 0.2.1已发布。这个答案是误导的。 (2认同)

Nel*_* G. 6

就我而言,我想要"value 是否包含 a{或 a },否则什么都不包含。例如:

 en:
   key1: value is 1
   key2: 'value is {1}'
Run Code Online (Sandbox Code Playgroud)

represent_str()要执行此操作,请从 PyYaml 模块中的文件representer.py复制函数,并在字符串包含{或 a时使用另一种样式}

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)
Run Code Online (Sandbox Code Playgroud)

要在您的代码中使用它:

import yaml

def represent_str(self, data):
  ...

yaml.add_representer(str, represent_str)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,键和值之间没有区别,这对我来说就足够了。如果您想要不同的键和值样式,请使用函数执行相同的操作represent_mapping


Hab*_*tsu 2

第一的

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

mapping = list(mapping.items())
    try:
        mapping = sorted(mapping)
    except TypeError:
        pass
Run Code Online (Sandbox Code Playgroud)

这就是顺序改变的原因

第二

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

概括

您可以基于“Dumper”创建自己的类并重载方法“represent_mapping”以更改字典的呈现方式

为了保存有关标量双引号的信息,您还必须基于“Loader”创建自己的类,但我担心它会影响其他类并且会变得困难