包含“-”的字符串总是用 ruamel.yaml 换行

Strings containing " - " always break onto newline with ruamel.yaml

我在 Python 3.7 项目中对 YAML 相当陌生,因此决定使用 ruamel.yaml 来让我入门。我打算用它来存储与一些视频文件相关的元数据。

我正在使用以下代码创建 YAML 文件:

data[filename] = [{'video': video_path},
                  {'key_frame': frame_path},
                  {'processed': get_timestamp()}]
yaml.dump(data, file_handle)

创建的 YAML 文件如下所示:

video.mp4:
- video: /Users/xyz/video.mp4
- key_frame: /Users/xyz/imgOutput/frame
    - Trigger.jpg
- processed: '2018-07-26 17:09:06'

问题是 key_frame 是一个名为 "frame - Trigger.jpg" 的文件。但是,该行总是在文件名中的“-”(即 space-破折号-space)处中断。结果是,作为一个人类可读的文件,它看起来非常错误。事实上,当它被读回时(使用 yaml.open),它被正确处理,并被视为一个单一的字符串文件名。只是 YAML 文件中的格式错误。

对原因有什么想法吗?这是预期的行为吗?我已经尝试了很多不同的方式来引用字符串,以防万一(这没有什么区别——即使引用它也会分割成一行),但从代码意义上讲,它从根本上是有效的——但作为 YAML 的大卖point 是人类可读的文件,最好了解是什么导致它以及如何修复它。

你能试试 str(frame_path)

data[filename] = [{'video': video_path}, {'key_frame': str(frame_path)}, {'processed': get_timestamp()}]

破折号没有什么特别之处。如果字符串长于某个阈值,它将在之后的第一个 space 处中断。您提供的示例不会为我重现此行为,但较长的字符串会重现。

生成的 YAML 有效。任何字符串,无论是否引用,都可以分成几行。

也许你可以在 ruamel 中调整阈值。不过,我在文档中找不到任何内容。

(另见我的文章Strings in YAML

在 YAML 中,纯标量(即没有单引号或双引号的标量)可以换行到空格上的缩进换行符。这就是正在发生的事情。

重现这个问题很困难,因为你的问题很不完整,但从输出中可以很容易地看出一些事情:

  • data 是一个 dict
  • filenamevideo_pathframe_path 被定义为字符串。
  • file_handle 可能是为了写入而打开的一些文件流。

其他的不太容易推导:

  • get_timestamp() 不是 return 一个 datetime.datetime() 实例,正如人们从它的名字中所期望的那样,而是一个字符串表示。为了防止这个字符串被解释为时间戳,它必须被引用。
  • 您正在使用默认 YAML() 实例(等于 typ='rt'),因为非默认实例将以流式(- {video: /Users/xyz/video.mp4} 等)编写叶映射

有了它和适当的 imports,您可以制作一个正常运行的程序:

import datetime
import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML(typ='rt')

def get_timestamp():
    return datetime.datetime(2018, 7, 26, 17, 9, 6).isoformat(sep=' ', timespec='seconds')

data = {}
filename = 'video.mp4'
video_path = '/Users/xyz/video.mp4'
frame_path = '/Users/xyz/imgOutput/frame - Trigger.jpg'
file_handle = sys.stdout

data[filename] = [{'video': video_path},
                  {'key_frame': frame_path},
                  {'processed': get_timestamp()}]
yaml.dump(data, file_handle)

这输出:

video.mp4:
- video: /Users/xyz/video.mp4
- key_frame: /Users/xyz/imgOutput/frame - Trigger.jpg
- processed: '2018-07-26 17:09:06'

所以我们忘记了一些东西,那就是:

yaml.width = 24  # range from 24-38 inclusive

你得到你的输出:

video.mp4:
- video: /Users/xyz/video.mp4
- key_frame: /Users/xyz/imgOutput/frame
    - Trigger.jpg
- processed: '2018-07-26 17:09:06'

所以只需删除 yaml.width = 行,您就应该一切就绪。


下次请提供一个最小但完整的功能程序,它可以实际生成输出。

我猜你的 frame_path 比你在这里显示的要长得多,而且你没有用户 xyz。这会导致您超过默认宽度(在发射器中定义为 80)和要环绕的普通标量。只需设置 yaml.width = 4096 或您的标量长度和嵌套深度所需的任何内容。

如果怀疑 YAML 输出是否正确,请将其读回(使用 YAML(typ='safe').load(input_stream),它应该会生成原始数据。