Дамп объекта в yaml без кавычек

#python #yaml #dump #pyyaml #ruamel.yaml

#python #yaml #дамп #pyyaml #ruamel.yaml

Вопрос:

У меня был какой-то объект, который я хочу превратить в yaml, единственное, что мне нужно, чтобы иметь возможность поместить в него «!что угодно» без кавычек.

Когда я пробую это с pyyaml, я получаю ‘!anything’ внутри моего файла yaml.

Я уже пробовал использовать ruamel.yaml сохранил scalarstring и LiteralScalarString. И это вроде как работает, но не так, как мне нужно работать. Дело в том, что в итоге я получаю yaml, который выглядит следующим образом:

 10.1.1.16:
            text: '1470814.27'
            confidence: |-
              !anything
  

Но мне не нужен этот |- символ.

Моя цель — получить yaml таким образом:

 10.1.1.16:
            text: '1470814.27'
            confidence: !anything
  

Есть идеи, как я могу этого добиться?

Комментарии:

1. В YAML !anything (и, как правило, все, что начинается с ! ) является тегом (т. Е. Не содержимым). Если вы хотите, !anything чтобы он обрабатывался как содержимое, вы должны использовать одинарные или двойные кавычки или скаляр блока ( |- или >- ).

2. @flyx итак, что мне делать, если я хочу иметь возможность дамп тега? Дело в том, что мне нужно каким-то образом иметь возможность записать его из моего кода на Python

Ответ №1:

Чтобы дамп пользовательского тега, вам необходимо определить тип и зарегистрировать представитель для этого типа. Вот как это сделать для скаляров:

 import yaml

class MyTag:
  def __init__(self, content):
    self.content = content

  def __repr__(self):
    return self.content

  def __str__(self):
    return self.content

def mytag_dumper(dumper, data):
  return dumper.represent_scalar("!anything", data.content)

yaml.add_representer(MyTag, mytag_dumper)

print(yaml.dump({"10.1.1.16": {
    "text": "1470814.27",
    "confidence": MyTag("")}}))
  

Это выдает

 10.1.1.16:
  confidence: !anything ''
  text: '1470814.27'
  

Обратите внимание на '' за тегом, который является помеченным скаляром (нет, вы не можете избавиться от него). Вы также можете помечать коллекции тегами, но вам нужно будет использовать represent_sequence или represent_mapping соответственно.

Комментарии:

1. Первая потоковая передача в буфер StringIO, а затем печать содержимого этого буфера излишне неэффективна (как с точки зрения потребления памяти, так и по времени) по сравнению с прямой потоковой передачей в sys.stdout . Поэтому вы всегда должны использовать yaml.dump(data, sys.stdout) вместо print(yaml.dump(data)) .

Ответ №2:

Вопреки комментарию @flix, в YAML вам не нужно заключать тег в одинарные или двойные кавычки (или скалярный блок). Вы можете попробовать анализатор ссылок Орена Бен-Кики (программно полученный из спецификации YAML), чтобы подтвердить, что ваш ожидаемый результат является действительным YAML.

Пустое содержимое обычно загружается как None в Python (как устаревшим PyYAML, так и ruamel.yaml). Помеченное пустое содержимое, конечно, может указывать только на существование определенного экземпляра без указания какого-либо значения.

ruamel.yaml вполне может выполнить ожидаемый результат в обратном направлении:

 import sys
from ruamel.yaml import YAML

yaml_str = """
10.1.1.16:
  text: '1470814.27'
  confidence: !anything
"""

yaml = YAML()
data = yaml.load(yaml_str)

yaml.dump(data, sys.stdout)
  

дает:

 10.1.1.16:
  text: '1470814.27'
  confidence: !anything
  

Вы можете сгенерировать объект, который сбрасывает только тег без значения с нуля (как это делает анализатор), но если вы не хотите вдаваться в подробности, вы можете просто загрузить помеченный объект и добавить его в свою структуру данных:

 import sys
import ruamel.yaml


yaml = ruamel.yaml.YAML()


def tagged_empty_scalar(tag):
   return yaml.load('!'   tag)

data = {'10.1.1.16': dict(text='1470814.27', confidence=tagged_empty_scalar('anything'))}

yaml.dump(data, sys.stdout)
  

Вы можете получить точно такой же результат в PyYAML и без кавычек, но это сложнее.