如何使 PyYAML 或 ruamel.yaml始终内联转储列表?无论是从现有文件加载的 YAML 元素列表还是从我的代码添加的 YAML 元素列表。
当我从文件加载 YAML 然后转储它时,它会转储内联列表(请参见下面的代码)。但是,如果我向现有父对象添加一个带有列表的新 YAML 元素,然后转储它,它会转储非内联列表。
我尝试使用 Python 3.7.3、PyYAML 5.1.1 和 ruamel.yaml 0.15.97。
>>> import ruamel.yaml
>>> ruamel.yaml.__version__
'0.15.97'
>>> raw_yaml = """
... users:
... user1:
... comment: comment1
... keys: ["user1 key1", "user1 key2"]
... groups: ["user1 group1", "user1 group2"]
... """
>>> yaml = ruamel.yaml.round_trip_load(raw_yaml, preserve_quotes=True)
>>> dump = ruamel.yaml.round_trip_dump(yaml, default_flow_style=None)
>>> print(dump)
users:
user1:
comment: comment1
keys: ["user1 key1", "user1 key2"]
groups: ["user1 group1", "user1 group2"]
# So far so good, 'keys' and 'groups' are dumped inline
>>> yaml['users']['user2'] = {}
>>> yaml['users']['user2']['comment'] = 'comment2'
>>> yaml['users']['user2']['keys'] = []
>>> yaml['users']['user2']['keys'].append('user2 key1')
>>> yaml['users']['user2']['keys'].append('user2 key2')
>>> yaml['users']['user2']['groups'] = []
>>> yaml['users']['user2']['groups'].append('user2 group1')
>>> yaml['users']['user2']['groups'].append('user2 group2')
>>> dump = ruamel.yaml.round_trip_dump(
... yaml, default_flow_style=False, default_style="'",
... indent=2, block_seq_indent=2)
# desired result:
# users:
# user1:
# comment: comment1
# keys: ["user1 key1", "user1 key2"]
# groups: ["user1 group1", "user1 group2"]
# user2:
# comment: comment2
# keys: ["user2 key1", "user2 key2"]
# groups: ["user2 group1", "user2 group2"]
>>> print(dump)
'users':
'user1':
'comment': 'comment1'
'keys': ["user1 key1", "user1 key2"]
'groups': ["user1 group1", "user1 group2"]
'user2':
'comment': 'comment2'
'keys':
- 'user2 key1'
- 'user2 key2'
'groups':
- 'user2 group1'
- 'user2 group2'
Run Code Online (Sandbox Code Playgroud)
参见上文,当我转储刚刚加载的 YAML (users['user1']) 时,列表是内联的:
keys: ["user1 key1", "user1 key2"]
groups: ["user1 group1", "user1 group2"]
Run Code Online (Sandbox Code Playgroud)
但是当我添加 users['user2'] 然后转储整个 YAML 对象时,列表不是内联的:
'keys':
- 'user2 key1'
- 'user2 key2'
'groups':
- 'user2 group1'
- 'user2 group2'
Run Code Online (Sandbox Code Playgroud)
如果我设置 'default_flow_style=True',它会内联转储整个元素:
'user2': {'comment': 'comment2', 'keys': ['user2 key1', 'user2 key2'], 'groups': [ 'user2 group1', 'user2 group2']}
Run Code Online (Sandbox Code Playgroud)
这不是我想要的。我希望将“评论”、“键”和“组”转储到单独的行上,并内联列表:
user2:
comment: comment2
keys: ["user2 key1", "user2 key2"]
groups: ["user2 group1", "user2 group2"]
Run Code Online (Sandbox Code Playgroud)
对于 PyYaml 来说,情况几乎是一样的。
我希望列表始终被内联转储(对于用户['user1'])。我怎么做?
您所说的内联在 YAML 文档中称为流式。ruamel.yaml 中都有一个选项 ( default_flow_style) 可以全局使用所有流样式、所有块样式或叶节点流样式(其余块样式)。这是 PyYAML 的旧行为。
然而,这不是您想要的,因为它会影响序列和映射,而您只需要映射。
ruamel.yaml,在往返模式下,可以保留文件中出现的单个流样式/块样式,因此您可以让例如离开节点及其父节点为流样式,或所有序列(Python列表)流样式和所有映射(Python 字典)块样式后者当然只有在映射不在序列“下方”时才有效,因为您不能在流样式中使用块样式。
如果您从头开始或使用具有正确格式的加载 YAML,只需确保任何添加的列表实际上是特殊的内部列表子类,用于ruamel.yaml保留注释、样式等并在添加的列表上设置流样式
import sys
import ruamel.yaml
from ruamel.yaml.scalarstring import DoubleQuotedScalarString as dq
def L(*l):
ret = ruamel.yaml.comments.CommentedSeq(l)
ret.fa.set_flow_style()
return ret
raw_yaml = """\
users:
user1:
comment: comment1
keys: ["user1 key1", "user1 key2"]
groups: ["user1 group1", "user1 group2"]
"""
yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
yaml.preserve_quotes = True
data = yaml.load(raw_yaml)
data['users']['user2'] = {}
data['users']['user2']['comment'] = 'comment2'
data['users']['user2']['keys'] = L()
data['users']['user2']['keys'].append('user2 key1')
data['users']['user2']['keys'].append('user2 key2')
data['users']['user2']['groups'] = L('abc', L('user2 group1', dq('user2 group2')))
# print(data)
yaml.dump(data, sys.stdout)
Run Code Online (Sandbox Code Playgroud)
这使:
users:
user1:
comment: comment1
keys: ["user1 key1", "user1 key2"]
groups: ["user1 group1", "user1 group2"]
user2:
comment: comment2
keys: [user2 key1, user2 key2]
groups: [abc, [user2 group1, "user2 group2"]]
Run Code Online (Sandbox Code Playgroud)
由于您希望每个列表都表示为流样式序列,因此还可以通过子类化表示器来更改所有列表的表示器,但上面的内容为您提供了更好的控制,并允许您准确地在流中流动那些您想要的列表-风格。
ruamel.yaml(和 PyYAML)使用流接口,而
print(dump(data))不是dump(data, sys.stdout)使转储完成到内存中的缓冲区,然后流式传输该缓冲区。这在时间和空间上都是低效率的,不要这样做。
| 归档时间: |
|
| 查看次数: |
5209 次 |
| 最近记录: |