【问题标题】:PyYAML not parsing all examplesPyYAML 不解析所有示例
【发布时间】:2019-05-28 10:57:35
【问题描述】:

我试图理解https://pyyaml.org/wiki/PyYAML 上的声明:

PyYAML features

- a complete YAML 1.1 parser. In particular, PyYAML can parse all 
  examples from the specification. 

如果您访问使用 PyYAML (http://yaml-online-parser.appspot.com/) 的在线 YAML 解析器,那么从规范中提取的几个示例不起作用

我了解您需要为其中一些故障定义标签,并且在线解析器只能处理单个文档 YAML,我知道在使用 PyYAML 时如何“修复”该问题。

但是示例 11 也失败了,它没有特殊标签并且是单个文档。 PyYAML 如何声称它可以解析所有示例,而它显然不能解析?这是因为 PyYAML 是针对 YAML 1.1 的,并且示例来自 YAML 1.2 规范吗?

【问题讨论】:

  • 这是因为......示例来自 [a later] 规范吗? 大概是的。实际的失败是密钥不可散列——pyyaml 将密钥读入列表而不是元组。可能 pyyaml 应该注意到该键被 作为 键使用,并对其进行元组化,尽管很难完全通用。
  • @torek 这些规范的示例是相同的(至少在第二章中),但是您对它为什么不加载的分析是正确的:PyYAML 在遇到时不会创建元组一个作为键的序列。当使用映射作为键时它也会失败,它应该创建为(哈希)collections.abc.Mapping
  • 就像 Anthon 所说,PyYAML 不能生成列表(元组)作为键,但我正在努力,希望它会出现在下一个版本中。然后它也可以使用嵌套元组作为键。

标签: python yaml pyyaml


【解决方案1】:

从你的最后一个问题开始:这是 不是 因为这些例子 来自后来的规范。假设你限制自己 规范中的预览章节/部分(在线解析器也是如此), 并考虑到我只比较了这些例子 视觉上(即不是基于字符的字符),示例 在第 2 章/第 2 节的 1.2 和 1.1 规范中是相同的。

您的误解来自于在 在线解析器的标题。它实际上试图做的是 load YAML,然后转储到 JSON、Python 或规范的 YAML。 加载中 PyYAML 由 YAML 中Processing Overview 图片中提到的阶段组成 规范(1.1 和 1.2 相同),从基于字符的 文档:解析、编写和构建步骤。

PyYAML 不会在解析步骤中失败,而是在构造中失败 步骤,因为(如@torek 所示)PyYAML 构造了一个 list 和 不能用作 Python dict 的键。这是一个 Python 的dict 实现的限制和IMO PyYAML 的缺陷之一。

import sys
import yaml as pyyaml

yaml_1_1_example_2_11 = """\
? - Detroit Tigers
  - Chicago cubs
:
  - 2001-07-23

? [ New York Yankees,
    Atlanta Braves ]
: [ 2001-07-02, 2001-08-12,
    2001-08-14 ]
"""

for event in pyyaml.parse(yaml_1_1_example_2_11):
    print(event)

给予:

StreamStartEvent()
DocumentStartEvent()
MappingStartEvent(anchor=None, tag=None, implicit=True)
SequenceStartEvent(anchor=None, tag=None, implicit=True)
ScalarEvent(anchor=None, tag=None, implicit=(True, False), value='Detroit Tigers')
ScalarEvent(anchor=None, tag=None, implicit=(True, False), value='Chicago cubs')
SequenceEndEvent()
SequenceStartEvent(anchor=None, tag=None, implicit=True)
ScalarEvent(anchor=None, tag=None, implicit=(True, False), value='2001-07-23')
SequenceEndEvent()
SequenceStartEvent(anchor=None, tag=None, implicit=True)
ScalarEvent(anchor=None, tag=None, implicit=(True, False), value='New York Yankees')
ScalarEvent(anchor=None, tag=None, implicit=(True, False), value='Atlanta Braves')
SequenceEndEvent()
SequenceStartEvent(anchor=None, tag=None, implicit=True)
ScalarEvent(anchor=None, tag=None, implicit=(True, False), value='2001-07-02')
ScalarEvent(anchor=None, tag=None, implicit=(True, False), value='2001-08-12')
ScalarEvent(anchor=None, tag=None, implicit=(True, False), value='2001-08-14')
SequenceEndEvent()
MappingEndEvent()
DocumentEndEvent()
StreamEndEvent()

所以 PyYAML 可以正确解析这个。不仅如此,如果在线“解析器” 不会尝试加载,然后转储,发出规范 YAML 时,它可以 处理这个例子(替换上面的最后两行 代码):

pyyaml.emit(pyyaml.parse(yaml_1_1_example_2_11), stream=sys.stdout, canonical=True)

因为这给出了:

---
{
  ? [
    ! "Detroit Tigers",
    ! "Chicago cubs",
  ]
  : [
    ! "2001-07-23",
  ],
  ? [
    ! "New York Yankees",
    ! "Atlanta Braves",
  ]
  : [
    ! "2001-07-02",
    ! "2001-08-12",
    ! "2001-08-14",
  ],
}

说 PyYAML 解析所有示例,就像我说我可以 读希腊文。我早在 70 年代就学会了希腊字母,所以我可以 阅读(该)希腊语(字符),但我不理解它们构成的单词。


ruamel.yaml(免责声明:我是那个包的作者)你可以加载这个例子,你甚至可以使用 PyYAML 转储加载的数据。

from pprint import pprint
import ruamel.yaml
import yaml as pyyaml

yaml = ruamel.yaml.YAML(typ='safe')
data = yaml.load(yaml_1_1_example_2_11)
pprint(data)
print('*' * 50)
yaml.dump(data, sys.stdout)
print('*' * 50)
pyyaml.safe_dump(data, sys.stdout)

因为它给出了:

{('Detroit Tigers', 'Chicago cubs'): [datetime.date(2001, 7, 23)],
 ('New York Yankees', 'Atlanta Braves'): [datetime.date(2001, 7, 2),
                                          datetime.date(2001, 8, 12),
                                          datetime.date(2001, 8, 14)]}
**************************************************
? [Detroit Tigers, Chicago cubs]
: [2001-07-23]
? [New York Yankees, Atlanta Braves]
: [2001-07-02, 2001-08-12, 2001-08-14]
**************************************************
? [Detroit Tigers, Chicago cubs]
: [2001-07-23]
? [New York Yankees, Atlanta Braves]
: [2001-07-02, 2001-08-12, 2001-08-14]

【讨论】:

    猜你喜欢
    • 2011-01-27
    • 2021-05-17
    • 2016-09-12
    • 1970-01-01
    • 2012-10-28
    • 2020-11-02
    • 2018-11-27
    • 2015-05-10
    • 1970-01-01
    相关资源
    最近更新 更多