Создание yaml / ruamel.yaml всегда создает дамп списков - PullRequest
2 голосов
/ 08 июля 2019

Как мне сделать 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 (users ['user1']), списки встроены:

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

Но когда я добавляю пользователей ['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 ситуация практически такая же.

Я хочу, чтобы списки всегда сбрасывались внутри строки (как для пользователей ['user1']). Как мне это сделать?

Ответы [ 2 ]

0 голосов
/ 09 июля 2019

То, что вы называете встроенным, называется стилем потока в YAML документация. Существует опция (default_flow_style) в обоих ruamel.yaml, чтобы во всем мире было все в стиле потока, все в стиле блока, или иметь стиль потока листовых узлов (блок отдыха стиль). Это старое поведение 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)

, что дает:

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

Поскольку вы хотите, чтобы каждый список был представлен как стиль потока последовательность, также можно изменить представление для всех списков, путем подкласса Представитель, но выше дает вам более точный контроль и позволяет передавать именно те списки, которые вы хотите, в стиле потока.


ruamel.yaml (и PyYAML) использовать потоковый интерфейс, делая print(dump(data)) вместо dump(data, sys.stdout) делает дамп быть сделано с буфером в памяти, а затем вы потоком этого буфера. это неэффективны во времени и пространстве, не делайте этого .

0 голосов
/ 08 июля 2019

Я могу ответить только за 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```
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...