Как прочитать пользовательский сериализованный объект YAML (написанный Rails) с помощью Python?

1

Я работаю с базой данных Rails, которая содержит сериализованные значения в одном столбце. Эти значения должны были быть обычными Hash es, но из-за неправильной дезинфекции параметров они были сохранены как HashWithIndifferentAccess или Parameters. Например, одна запись столбца выглядит следующим образом:

--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  windowHeight: 946
  documentHeight: 3679
  scrollTop: 500
permitted: false

Я хочу прочитать это с реализацией Python yaml, но когда я попытаюсь это сделать, я получаю:

*** yaml.constructor.ConstructorError: could not determine a constructor for the tag '!ruby/object:ActionController::Parameters'
  in "<unicode string>", line 1, column 5:
    --- !ruby/object:ActionController::P ...
        ^

Поэтому по какой-то причине он ожидает конструктора. Но вполне очевидно, что сама ценность - это просто обычный словарь. Как я могу его прочитать?

Теги:
yaml
pyyaml

1 ответ

1
Лучший ответ

Вы можете использовать add_constructor(loader, node) парсера PyYAML, которая позволяет вам создавать пользовательские конструкторы для типов объектов, которые он не распознает.

В этом конструкторе функцию loader.construct_pairs(node) можно вызвать для получения кортежей с ключом из исходного содержимого узла. Используя понимание словаря, мы можем создать оригинальный словарь.

Поскольку запись вложенна, мы должны применить конструктор к обоим типам объектов.

Полный пример:

import yaml

def convert_entry(loader, node):
    return { e[0]: e[1] for e in loader.construct_pairs(node) }

yaml.add_constructor('!ruby/hash:ActiveSupport::HashWithIndifferentAccess', convert_entry)
yaml.add_constructor('!ruby/object:ActionController::Parameters', convert_entry)

yaml.load(input_string)

Это как- то документировано, но трудно найти много примеров.

  • 0
    Есть ли шанс получить код Rails, исправленный в правильно YAMLizied params ? Они, вероятно, хотят сказать params.to_unsafe_h.to_yaml вместо params.to_yaml .
  • 1
    @muistooshort Да, именно это мы и сделали для новых записей - медленно переводим старые в правильный формат, но это занимает некоторое время.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню