Python PyYAML 转储格式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20805418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 21:16:03  来源:igfitidea点击:

PyYAML dump format

pythonpython-3.xyamlquotespyyaml

提问by nicosantangelo

I know there are a few questions about this on SO, but I couldn't find what I was looking for.

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

I'm using pyyamlto read (.load()) a .ymlfile, modify or add a key, and then write it (.dump()) again. The problem is that I want to keep the file format post-dump, but it changes.

我正在使用pyyaml读取 ( .load()).yml文件、修改或添加密钥,然后.dump()再次写入 ( )。问题是我想保留转储后的文件格式,但它发生了变化。

For example, I edit the key en.test.index.fewto say "Bye"instead of "Hello"

例如,我编辑键en.test.index.few"Bye"代替"Hello"

Python:

Python:

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

Then, afther changing the key:

然后,更改密钥后:

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:

亚姆:

Before:

前:

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

After:

后:

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

Is there a way to keep the same format?, for example the qoutes and order. Am I using the wrong tool for this?

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

I know maybe the original file it's not entirely correct, but I have no control over it (it's a Ruby on Rails i18n file).

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

Thank you very much.

非常感谢。

回答by Habibutsu

First

第一的

To represent dictionary data is used following code:

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

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

It is why ordering is changed

这就是更改顺序的原因

Second

第二

Information about how scalar type was presented (with double quote or not) is lost when reading (this is principal approach of library)

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

Summary

概括

You can create own class based on 'Dumper' and to overload method 'represent_mapping' for changing behaviour how dictionary will be presented

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

For saving information about double quotes for scalar you must also create own class based on 'Loader', but i am afraid that it will affect and other classes and will doing it difficult

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

回答by Cecil Curry

Below, ruamel.yamlis used instead.

下面,ruamel.yaml改为使用。

ruamel.yamlis actively maintained. Unlike PyYAML, ruamel.yamlsupports:

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

  • YAML <= 1.2.PyYAML only supports YAML <= 1.1. This is vital, as YAML 1.2 intentionally breaks backward compatibilitywith YAML 1.1 in several edge cases. This would usually be a bad thing. In this case, this renders YAML 1.2 a strict superset of JSON. Since YAML 1.1 is nota strict superset of JSON, this is a good thing.
  • Roundtrip preservation.When calling yaml.dump()to dump a dictionary loaded by a prior call to yaml.load():
    • PyYAML naively ignores all input formatting – including comments, ordering, quoting, and whitespace. Discarded like so much digital refuse into the nearest available bit bucket.
    • ruamel.yamlcleverly respects allinput formatting. Everything. The whole stylistic enchilada. The entire literary shebang. All.
  • 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巧妙地尊重所有输入格式。一切。整个风格的辣酱玉米饼馅。整个文学社邦。全部。

Library Migration: The Trail of Code Tears

库迁移:代码眼泪的踪迹

Since ruamel.yamlis a PyYAML fork and hence conforms to the PyYAML API, switching from PyYAML to ruamel.yamlin existing applications is typically as simple as:

由于ruamel.yaml是 PyYAML 分支,因此符合 PyYAML API,从 PyYAML 切换到ruamel.yaml现有应用程序通常非常简单:

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

That's it.

就是这样。

No other changes should be needed. The yaml.load()and yaml.dump()functions should continue to behave as expected – with the added benefits of now supporting YAML 1.2 and actively receiving bug fixes.

不需要其他更改。在yaml.load()yaml.dump()职能应该继续像预期的那样-与现在支持YAML 1.2,并积极接受bug修复的额外的好处。

Roundtrip Preservation and What It Can Do for You

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

For backward compatibility with PyYaml, the yaml.load()and yaml.dump()functions do notperform roundtrip preservation by default. To do so, explicitly pass:

为了与 PyYaml 向后兼容,默认情况下yaml.load()yaml.dump()函数执行往返保留。为此,显式传递:

  • The optional Loader=ruamel.yaml.RoundTripLoaderkeyword parameter to yaml.load().
  • The optional Dumper=ruamel.yaml.RoundTripDumperkeyword parameter to yaml.dump().
  • 可选的Loader=ruamel.yaml.RoundTripLoader关键字参数yaml.load()
  • 可选的Dumper=ruamel.yaml.RoundTripDumper关键字参数yaml.dump()

An example kindly "borrowed" from ruamel.yamldocumentation:

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='')

It is done.Comments, ordering, quoting, and whitespace will now be preserved intact.

完成了。注释、排序、引用和空格现在将完整保留。

回答by Nelson G.

In my case, I want "if value contains a {or a }, otherwise nothing. For example:

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

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

To perform that, copy function represent_str()from file representer.pyin module PyYaml and use another style if string contains {or a }:

要执行此操作,请represent_str()从PyYaml 模块中的文件代表.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)

To use it in your code:

要在您的代码中使用它:

import yaml

def represent_str(self, data):
  ...

yaml.add_representer(str, represent_str)

In this case, no diffences between keys and values and that's enough for me. If you want a different style for keys and values, perform the same thing with function represent_mapping

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

回答by ChaosPredictor

I have tried lot's of stuff, and finally moved to JSON, sorry.

我尝试了很多东西,最后转向了 JSON,抱歉。