使yaml / ruamel.yaml总是内联转储列表

时间:2019-07-08 15:01:06

标签: python yaml

如何使PyYAML或ruamel.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'

请参阅上文,当我转储刚加载的YAML(用户['user1'])时,列表是内联的:

keys: ["user1 key1", "user1 key2"]
groups: ["user1 group1", "user1 group2"]

但是当我添加users ['user2']然后转储整个YAML对象时,列表不是内联的:

'keys':
    - 'user2 key1'
    - 'user2 key2'
'groups':
    - 'user2 group1'
    - 'user2 group2'

如果我设置'default_flow_style = True',它将内联转储整个元素:

'user2': {'comment': 'comment2', 'keys': ['user2 key1', 'user2 key2'], 'groups': [ 'user2 group1', 'user2 group2']}

这不是我想要的。我想将“注释”,“键”和“组”转储到带有内联列表的单独行上:

user2:
  comment: comment2
  keys: ["user2 key1", "user2 key2"]
  groups: ["user2 group1", "user2 group2"]

对于PyYaml,情况实际上是相同的。

我希望列表始终以内联方式转储(对于users ['user1'])。我该怎么办?

2 个答案:

答案 0 :(得分:0)

我只能回答PyYAML: 该行为在5.1版中已更改。

https://github.com/yaml/pyyaml/pull/256

False将始终输出块样式。 True将始终输出流样式。 None将仅针对包含以下内容的集合输出流样式 仅标量。

False现在是默认设置,因为许多用户抱怨以前的默认设置None不合适。

因此,您需要default_flow_style=None来使用PyYAML。

data = dict( a=dict(aa=dict(aaa = ['x','y']), ab=42) )
print( yaml.dump( data ) )
print( yaml.dump( data, default_flow_style=True ) )
print( yaml.dump( data, default_flow_style=False ) )
print( yaml.dump( data, default_flow_style=None ) )

输出:

a:
  aa:
    aaa:
    - x
    - y
  ab: 42

{a: {aa: {aaa: [x, y]}, ab: 42}}

a:
  aa:
    aaa:
    - x
    - y
  ab: 42

a:
  aa:
    aaa: [x, y]
  ab: 42```

答案 1 :(得分:0)

您在YAML中将内联称为流样式 文档。两者中都有一个选项(default_flow_style) ruamel.yaml在全球范围内拥有所有流样式, 一切都是块样式,或者具有叶节点流样式(其余块 样式)。这是PyYAML的旧行为。

但是这不是您想要的,因为它会影响序列和 映射,而您只需要映射。

ruamel.yaml在往返模式下可以保留单个 流样式/块样式,因为它们出现在文件中,因此您可以 例如离开节点及其父节点为流式或所有序列 (Python列表)流样式和所有映射(Python dict)块样式 后者当然仅在映射不在“下”时有效 顺序,因为您不能在流样式中拥有块样式。

如果从头开始或使用正确格式的已加载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)

给出:

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"]]

因为您希望每个列表都以流样式表示 顺序,也可以更改所有列表的代表, 通过将Representer子类化,但是以上内容使您可以更好地控制 并允许您以流样式准确地流动所需的那些列表。


ruamel.yaml(和PyYAML)使用流接口, 使用print(dump(data))而不是dump(data, sys.stdout)进行转储 对内存中的缓冲区进行处理,然后对该缓冲区进行流式处理。它是 时间和空间效率低下,不要这样做