Как восстановить сломанный дамп питона "cPickle"? - PullRequest
2 голосов
/ 20 марта 2009

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

Traceback (most recent call last):
  File "/usr/share/rss2email/rss2email.py", line 740, in <module>
    elif action == "list": list()
  File "/usr/share/rss2email/rss2email.py", line 681, in list
    feeds, feedfileObject = load(lock=0)
  File "/usr/share/rss2email/rss2email.py", line 422, in load
    feeds = pickle.load(feedfileObject)
TypeError: ("'str' object is not callable", 'sxOYAAuyzSx0WqN3BVPjE+6pgPU', ((2009, 3, 19, 1, 19, 31, 3, 78, 0), {}))

Единственный полезный факт, который мне удалось построить из этого обратного следа, - это то, что файл ~/.rss2email/feeds.dat, в котором rss2email сохраняет всю свою конфигурацию и состояние времени выполнения, каким-то образом нарушен. Очевидно, rss2email читает его состояние и выдает его обратно, используя cPickle при каждом запуске.

Я даже нашел строку, содержащую упомянутую выше строку 'sxOYAAuyzSx0WqN3BVPjE+6pgPU' в гигантском (> 12 МБ) файле feeds.dat. На мой неподготовленный взгляд, свалка не выглядит усеченной или поврежденной иным образом.

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

Версия Python 2.5.4 для Debian / нестабильная система.

EDIT

Питер Гибсон и Дж.Ф. Себастьян предложили напрямую загрузить из маринованный файл, и я пробовал это раньше. Видимо, класс Feed это определено в rss2email.py, так что вот мой сценарий:

#!/usr/bin/python

import sys
# import pickle
import cPickle as pickle
sys.path.insert(0,"/usr/share/rss2email")
from rss2email import Feed

feedfile = open("feeds.dat", 'rb')
feeds = pickle.load(feedfile)

«Простой» вариант рассола производит следующий возврат:

Traceback (most recent call last):
  File "./r2e-rescue.py", line 8, in <module>
    feeds = pickle.load(feedfile)
  File "/usr/lib/python2.5/pickle.py", line 1370, in load
    return Unpickler(file).load()
  File "/usr/lib/python2.5/pickle.py", line 858, in load
    dispatch[key](self)
  File "/usr/lib/python2.5/pickle.py", line 1133, in load_reduce
    value = func(*args)
TypeError: 'str' object is not callable

Вариант cPickle производит практически то же самое, что и вызов r2e само по себе:

Traceback (most recent call last):
  File "./r2e-rescue.py", line 10, in <module>
    feeds = pickle.load(feedfile)
TypeError: ("'str' object is not callable", 'sxOYAAuyzSx0WqN3BVPjE+6pgPU', ((2009, 3, 19, 1, 19, 31, 3, 78, 0), {}))

РЕДАКТИРОВАТЬ 2

Следуя предложению Дж.Ф. Себастьяна, поставить "printf" отладка "в Feed.__setstate__ в мой тестовый скрипт, это последние несколько строк перед выходом Python.

          u'http:/com/news.ars/post/20080924-everyone-declares-victory-in-smutfree-wireless-broadband-test.html': u'http:/com/news.ars/post/20080924-everyone-declares-victory-in-smutfree-wireless-broadband-test.html'},
 'to': None,
 'url': 'http://arstechnica.com/'}
Traceback (most recent call last):
  File "./r2e-rescue.py", line 23, in ?
    feeds = pickle.load(feedfile)
TypeError: ("'str' object is not callable", 'sxOYAAuyzSx0WqN3BVPjE+6pgPU', ((2009, 3, 19, 1, 19, 31, 3, 78, 0), {}))

То же самое происходит в Debian / etch box, использующем python 2.4.4-2.

Ответы [ 4 ]

5 голосов
/ 05 апреля 2009

Как я решил свою проблему

Порт Perl pickle.py

После комментария Дж. Ф. Себастьяна о том, как просто формат, я вышел в части порта pickle.py для Perl. Пара быстрых регулярных выражений был бы более быстрый способ получить доступ к моему данных, но я чувствовал, что ценность хака и возможность узнать больше о Питоне стоило бы того. Плюс, я все еще чувствую себя намного больше удобное использование (и отладка кода в) Perl, чем Python.

Большая часть усилий по переносу (простые типы, кортежи, списки, словари) пошел очень просто. Perl и Python разные понятия классы и объекты были единственной проблемой до сих пор, где немного больше чем простой перевод идиом. Результатом является модуль называется Pickle::Parse, который после небольшой полировки будет опубликовано на CPAN.

Модуль под названием Python::Serialise::Pickle существовал в CPAN, но я обнаружил, что ему не хватает возможностей для синтаксического анализа: и не поддерживает классы / объекты.

Разбор, преобразование данных, обнаружение фактических ошибок в потоке

Основываясь на Pickle::Parse, я попытался проанализировать файл feeds.dat. После нескольких итераций исправления тривиальных ошибок в моем коде синтаксического анализа, я получил сообщение об ошибке, поразительно похожее на оригинал pickle.py объект не может быть вызван сообщение об ошибке:

Can't use string ("sxOYAAuyzSx0WqN3BVPjE+6pgPU") as a subroutine
ref while "strict refs" in use at lib/Pickle/Parse.pm line 489,
<STDIN> line 187102.

Ха! Теперь мы находимся в точке, где вполне вероятно, что фактические данные Поток сломан. Кроме того, мы получаем представление , где оно сломано.

Оказалось, что первая строка следующей последовательности была неправильной:

g7724
((I2009
I3
I19
I1
I19
I31
I3
I78
I0
t(dtRp62457

Позиция 7724 в «записке» указывает на эту строку "sxOYAAuyzSx0WqN3BVPjE+6pgPU". Из аналогичных записей ранее в было ясно, что нужен объект time.struct_time вместо. Все последующие записи разделяли этот неправильный указатель. С простым Операция поиска / замены, это было тривиально исправить.

Мне кажется странным, что я нашел источник ошибки случайно через функцию Perl, которая сообщает пользователю свою позицию на входе поток данных, когда он умирает.

Заключение

  1. Я отойду от rss2email, как только найду время автоматически преобразует свою маринованную конфигурацию / состояние беспорядка в формат другого инструмента.
  2. pickle.py нужны более значимые сообщения об ошибках, которые сообщают пользователю о положении потока данных (не само по себе код), где что-то идет не так.
  3. Перенос частей pickle.py на Perl был увлекательным и, в конце концов, полезным.
3 голосов
/ 20 марта 2009

Вы пытались вручную загрузить файл feeds.dat, используя cPickle и pickle? Если выходные данные отличаются, это может указывать на ошибку.

Что-то вроде (из вашего домашнего каталога):

import cPickle, pickle
f = open('.rss2email/feeds.dat', 'r')
obj1 = cPickle.load(f)
obj2 = pickle.load(f)

(вам может потребоваться открыть в двоичном режиме 'rb', если rss2email не работает в ascii).

Пит

Edit: тот факт, что cPickle и pickle выдают одинаковую ошибку, говорит о том, что проблема в файле feeds.dat. Вероятно, изменение класса Feed между версиями rss2email, как предложено в ошибке Ubuntu, на которую ссылается J.F. Sebastian.

2 голосов
/ 20 марта 2009
  1. 'sxOYAAuyzSx0WqN3BVPjE+6pgPU', скорее всего, не имеет отношения к проблеме маринада
  2. Опубликовать трассировку ошибки для (чтобы определить, какой класс определяет атрибут, который не может быть вызван (тот, который приводит к TypeError):

    python -c "import pickle; pickle.load(open('feeds.dat'))"
    

EDIT:

Добавьте следующее в ваш код и запустите (перенаправьте stderr в файл, затем используйте 'tail -2' для печати последних 2 строк):

from pprint import pprint
def setstate(self, dict_):
    pprint(dict_, stream=sys.stderr, depth=None)
    self.__dict__.update(dict_)
Feed.__setstate__ = setstate

Если вышеприведенное не дает интересного результата, используйте общую тактику устранения неполадок:

Подтвердите, что 'feeds.dat' является проблемой:

  • резервная копия ~/.rss2email каталог
  • установите rss2email в изолированную программную среду virtualenv / pip (или используйте zc.buildout), чтобы изолировать среду (убедитесь, что вы используете feedparser.py из транка).
  • добавить пару каналов, добавлять каналы, пока размер 'feeds.dat' не станет больше текущего. Запустите несколько тестов.
  • попробуйте старый 'feeds.dat'
  • попробуйте новый 'feeds.dat' в существующей установке rss2email

См. r2e выдает ошибку TypeError в Ubuntu.

2 голосов
/ 20 марта 2009

Звучит так, будто внутренности cPickle запутываются. Эта тема (http://bytes.com/groups/python/565085-cpickle-problems) выглядит так, как будто может иметь ключ ..

...