Как я могу контролировать, какую скалярную форму PyYAML использует для моих данных?

У меня есть объект с коротким строковым атрибутом и длинным многострочным атрибутом строки. Я хочу написать короткую строку в виде скаляризованного YAML-скаляра, а многострочную строку как литерал-скаляр:

my_obj.short = "Hello" my_obj.long = "Line1\nLine2\nLine3" 

Я бы хотел, чтобы YAML выглядел так:

 short: "Hello" long: | Line1 Line2 Line3 

Как я могу дать указание PyYAML сделать это? Если я вызываю yaml.dump(my_obj) , он выдает yaml.dump(my_obj) вывод:

 {long: 'line1 line2 line3 ', short: Hello} 

(Не знаю, почему длинный двойной промежуток …)

Могу ли я диктовать PyYAML, как обрабатывать мои атрибуты? Я хотел бы повлиять на порядок и стиль.

4 Solutions collect form web for “Как я могу контролировать, какую скалярную форму PyYAML использует для моих данных?”

На основе каких-либо библиотек yaml в Python, которые поддерживают демпинг длинных строк как блок-листы или сложенные блоки?

 import yaml from collections import OrderedDict class quoted(str): pass def quoted_presenter(dumper, data): return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"') yaml.add_representer(quoted, quoted_presenter) class literal(str): pass def literal_presenter(dumper, data): return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') yaml.add_representer(literal, literal_presenter) def ordered_dict_presenter(dumper, data): return dumper.represent_dict(data.items()) yaml.add_representer(OrderedDict, ordered_dict_presenter) d = OrderedDict(short=quoted("Hello"), long=literal("Line1\nLine2\nLine3\n")) print(yaml.dump(d)) 

Вывод

 short: "Hello" long: | Line1 Line2 Line3 

Мне нужен любой ввод с \n в нем, чтобы быть блочным литералом. Используя код в yaml/representer.py в качестве базы, я получил:

 # -*- coding: utf-8 -*- import yaml def should_use_block(value): for c in u"\u000a\u000d\u001c\u001d\u001e\u0085\u2028\u2029": if c in value: return True return False def my_represent_scalar(self, tag, value, style=None): if style is None: if should_use_block(value): style='|' else: style = self.default_style node = yaml.representer.ScalarNode(tag, value, style=style) if self.alias_key is not None: self.represented_objects[self.alias_key] = node return node a={'short': "Hello", 'multiline': """Line1 Line2 Line3 """, 'multiline-unicode': u"""Lêne1 Lêne2 Lêne3 """} print(yaml.dump(a)) print(yaml.dump(a, allow_unicode=True)) yaml.representer.BaseRepresenter.represent_scalar = my_represent_scalar print(yaml.dump(a)) print(yaml.dump(a, allow_unicode=True)) 

Вывод

 {multiline: 'Line1 Line2 Line3 ', multiline-unicode: "L\xEAne1\nL\xEAne2\nL\xEAne3\n", short: Hello} {multiline: 'Line1 Line2 Line3 ', multiline-unicode: 'Lêne1 Lêne2 Lêne3 ', short: Hello} After override multiline: | Line1 Line2 Line3 multiline-unicode: "L\xEAne1\nL\xEAne2\nL\xEAne3\n" short: Hello multiline: | Line1 Line2 Line3 multiline-unicode: | Lêne1 Lêne2 Lêne3 short: Hello 

Влюбившись в подход @ lbt , я получил этот код:

 import yaml def str_presenter(dumper, data): if len(data.splitlines()) > 1: # check for multiline string return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') return dumper.represent_scalar('tag:yaml.org,2002:str', data) yaml.add_representer(str, str_presenter) 

Он делает каждую многострочную строку блочным литералом.

Я пытался избежать частичной патчей обезьян. Полный кредит для @lbt и @JFSebastian.

Вы можете использовать ruamel.yaml и его RoundTripLoader / Dumper (отказ от ответственности: я автор этого пакета), кроме того, что вы хотите, он поддерживает спецификацию YAML 1.2 (с 2009 года) и имеет ряд других улучшений:

 import sys import ruamel.yaml as yaml yaml_str = """\ short: "Hello" # does keep the quotes, but need to tell the loader long: | Line1 Line2 Line3 """ data = yaml.round_trip_load(yaml_str, preserve_quotes=True) yaml.round_trip_dump(data, sys.stdout) 

дает:

 short: "Hello" # does keep the quotes, but need to tell the loader long: | Line1 Line2 Line3 

(включая комментарий, начиная с той же колонки, что и раньше)

  • Conda 'ImportError: нет модуля с именем ruamel.yaml.comments'
  • Синтаксис YAML для Salt и Python
  • Есть ли способ построить объект, используя PyYAML construct_mapping после того, как все узлы завершат загрузку?
  • Переносимые переменные записи в файл YAML
  • ConfigObj / ConfigParser против использования файла настроек YAML для Python
  • Параметры конструктора по умолчанию в pyyaml
  • Как указать параметр сериализатора параметров запроса в django-rest-swagger?
  • Как создать объект datetime с помощью PyYAML
  •  
    Interesting Posts for Van-Lav
    Python - лучший язык программирования в мире.