包含“-”的字符串总是用 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
filename
、video_path
和 frame_path
被定义为字符串。
file_handle
可能是为了写入而打开的一些文件流。
其他的不太容易推导:
get_timestamp()
不是 return 一个 datetime.datetime()
实例,正如人们从它的名字中所期望的那样,而是一个字符串表示。为了防止这个字符串被解释为时间戳,它必须被引用。
- 您正在使用默认
YAML()
实例(等于 typ='rt'
),因为非默认实例将以流式(- {video: /Users/xyz/video.mp4}
等)编写叶映射
有了它和适当的 import
s,您可以制作一个正常运行的程序:
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)
,它应该会生成原始数据。
我在 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
filename
、video_path
和frame_path
被定义为字符串。file_handle
可能是为了写入而打开的一些文件流。
其他的不太容易推导:
get_timestamp()
不是 return 一个datetime.datetime()
实例,正如人们从它的名字中所期望的那样,而是一个字符串表示。为了防止这个字符串被解释为时间戳,它必须被引用。- 您正在使用默认
YAML()
实例(等于typ='rt'
),因为非默认实例将以流式(- {video: /Users/xyz/video.mp4}
等)编写叶映射
有了它和适当的 import
s,您可以制作一个正常运行的程序:
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)
,它应该会生成原始数据。