Подтвердить что ты не робот

Добавление комментариев к YAML, созданных с помощью PyYaml

Я создаю документы Ямля из своих собственных объектов python с помощью PyYaml. например, мой объект:

class MyObj(object):
    name = "boby"
    age = 34

становится:

boby:
   age: 34

Пока все хорошо.

Но я не нашел способ программно добавлять комментарии к выпущенному yaml, чтобы он выглядел так:

boby:       # this is the name
   age: 34  # in years

Глядя на документацию PyYaml, а также на код, я не нашел способа сделать это.

Любые предложения?

4b9b3361

Ответ 1

Вероятно, у вас есть представитель класса MyObj, поскольку по умолчанию демпинг (print(yaml.dump(MyObj()))) с PyYAML даст вам:

!!python/object:__main__.MyObj {}

PyYAML может делать только одну вещь с комментариями в вашем желаемом выходе: отбросьте их. Если вы будете читать этот желаемый результат, вы закончите с тегом, содержащим dict ({'boby': {'age': 34}}, вы не получите экземпляр MyObj(), потому что нет информации о теге)

Расширенная версия PyYAML, которую я разработал (ruamel.yaml), может читать в YAML с комментариями, сохранять комментарии и писать комментарии, когда демпинг. Если вы прочтете свой желаемый результат, результирующие данные будут выглядеть (и действовать) как dict, содержащие dict, но на самом деле существует более сложная структура данных, которая может обрабатывать комментарии. Однако вы можете создать эту структуру, когда ruamel.yaml попросит вас сбросить экземпляр MyObj, и если вы добавите комментарии в это время, вы получите желаемый результат.

from __future__ import print_function

import sys
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap


class MyObj():
    name = "boby"
    age = 34

    def convert_to_yaml_struct(self):
        x = CommentedMap()
        a = CommentedMap()
        x[data.name] = a
        x.yaml_add_eol_comment('this is the name', 'boby', 11)
        a['age'] = data.age
        a.yaml_add_eol_comment('in years', 'age', 11)
        return x

    @staticmethod
    def yaml_representer(dumper, data, flow_style=False):
        assert isinstance(dumper, ruamel.yaml.RoundTripDumper)
        return dumper.represent_dict(data.convert_to_yaml_struct())


ruamel.yaml.RoundTripDumper.add_representer(MyObj, MyObj.yaml_representer)

ruamel.yaml.round_trip_dump(MyObj(), sys.stdout)

Какие принты:

boby:      # this is the name
  age: 34  # in years

Нет необходимости ждать с созданием экземпляров CommentedMap, пока вы не захотите представить экземпляр MyObj. Я бы, например, make name и age в свойствах, которые получают/устанавливают значения из/на подходящем CommentedMap. Таким образом, вы могли бы легко добавить комментарии перед тем, как статический метод yaml_representer вызывается для представления экземпляра MyObj.