如何恢复损坏的python“cPickle”转储?

时间:2009-03-19 23:25:04

标签: python rss pickle

我正在使用rss2email将大量RSS Feed转换为邮件以便于使用。也就是说,我 使用它,因为它今天以一种可怕的方式破坏了:每次运行时,它只给我这个回溯:

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将其转储回来。

我甚至在巨型(&gt; 12MB)'sxOYAAuyzSx0WqN3BVPjE+6pgPU'文件中找到了包含上述feeds.dat字符串的行。对于我未经训练的眼睛,转储似乎没有被截断或以其他方式损坏。

我可以尝试哪些方法来重建文件?

Debian / unstable系统上的Python版本是2.5.4。

修改

彼得吉布森和J.F.塞巴斯蒂安建议直接装载 泡菜文件,我之前尝试过。显然,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

遵循J.F.塞巴斯蒂安关于推出“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), {}))

使用python 2.4.4-2在Debian / etch框中也会发生同样的事情。

4 个答案:

答案 0 :(得分:5)

我如何解决我的问题

Perl端口pickle.py

按照J.F. Sebastian关于pickle多么简单的评论 格式是,我出去将pickle.py的部分移植到Perl。一对夫妇 快速正则表达式可以更快地访问我的 数据,但我觉得黑客价值和学习更多的机会 关于Python将是值得的。另外,我还有更多感受 很容易使用(和调试代码)Perl比Python。

大多数移植工作(简单类型,元组,列表,词典) 非常直截了当Perl和Python的不同概念 到目前为止,类和对象是唯一的问题 比起简单的习语翻译需要。结果是一个模块 称为Pickle::Parse,经过一些抛光后即可完成 发表于CPAN。

CPAN上存在一个名为Python::Serialise::Pickle的模块,但是我 发现它的解析能力不足:它全部调试输出 在这个地方,似乎不支持类/对象。

解析,转换数据,检测流中的实际错误

基于Pickle::Parse,我尝试解析feeds.dat文件。 经过几次修复我的解析代码中的琐碎错误后,我得到了 与pickle.py原始内容极为相似的错误消息 object not callable 错误消息:

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需要更有意义的错误消息来告诉用户 关于数据流的位置(而不是它自己的poision) 代码)出了问题。
  3. 将部件pickle.py移植到Perl很有趣,最后还是奖励。

答案 1 :(得分:3)

您是否尝试过使用cPickle和pickle手动加载feeds.dat文件?如果输出不同,则可能暗示错误。

(来自您的主目录):

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

(如果rss2email没有在ascii中发帖,你可能需要以二进制模式'rb'打开。)

皮特

编辑:cPickle和pickle给出相同错误这一事实表明feeds.dat文件存在问题。可能是在rss2email版本之间Feed类的变化,如Ubuntu漏洞J.F. Sebastian链接到。

答案 2 :(得分:2)

听起来cPickle的内部人员正在纠缠不清。这个帖子(http://bytes.com/groups/python/565085-cpickle-problems)看起来可能有线索..

答案 3 :(得分:2)

  1. 'sxOYAAuyzSx0WqN3BVPjE+6pgPU'很可能与pickle的问题无关
  2. 发布错误回溯(确定哪个类定义了无法调用的属性(导致TypeError的属性):

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

    将以下内容添加到您的代码中并运行(将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)。
    • 添加多个Feed,添加Feed,直到'feeds.dat'大小超过当前值。进行一些测试。
    • 尝试旧'feeds.dat'
    • 在现有的rss2email安装上尝试新的“feeds.dat”

    请参阅Ubuntu上的r2e bails out with TypeError错误。