3

我正在使用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.datrss2email显然,rss2email读取它的状态并cPickle在每次运行时将其转储回去。

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

我可以尝试什么方法来重建文件?

Python 版本在 Debian/unstable 系统上为 2.5.4。

编辑

Peter Gibson 和 JF Sebastian 建议直接从 pickle 文件加载,我之前尝试过。显然,需要一个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

按照 JF Sebastian 的建议,将“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

4 回答 4

6

我如何解决我的问题

Perl 端口pickle.py

在 JF Sebastian 关于pickle 格式简单的评论之后,我开始将部分内容移植pickle.py到 Perl。几个快速的正则表达式本来是访问我的数据的一种更快的方法,但我觉得 hack 的价值和学习更多关于 Python 的机会是值得的。另外,我仍然觉得使用 Perl(和调试代码)比使用 Python 更舒服。

大多数移植工作(简单类型、元组、列表、字典)都非常简单。到目前为止,Perl 和 Python 的类和对象的不同概念是唯一需要不仅仅是简单翻译成语的问题。结果是一个名为的模块Pickle::Parse,经过一些改进后将在 CPAN 上发布。

在 CPAN 上存在一个名为的模块Python::Serialise::Pickle,但我发现它缺乏解析能力:它会到处喷出调试输出,而且似乎不支持类/对象。

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

基于Pickle::Parse,我尝试解析feeds.dat文件。在我的解析代码中修复了一些微不足道的错误之后,我收到了一条错误消息,该错误消息与pickle.py's original 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需要更有意义的错误消息来告诉用户数据流的位置(而不是它自己的代码中的位置)哪里出错了。
  3. 将部件移植pickle.py到 Perl 很有趣,而且最终也很有收获。
于 2009-04-05T18:49:16.087 回答
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 文件是问题所在。正如 Ubuntu bug JF Sebastian 链接中所建议的那样,可能是 rss2email 版本之间的 Feed 类发生了变化。

于 2009-03-20T00:40:19.880 回答
2

听起来 cPickle 的内部结构变得复杂起来。该线程(http://bytes.com/groups/python/565085-cpickle-problems)看起来可能有线索..

于 2009-03-20T00:46:26.030 回答
2
  1. 'sxOYAAuyzSx0WqN3BVPjE+6pgPU'很可能与泡菜的问题无关
  2. 发布错误回溯(以确定哪个类定义了无法调用的属性(导致 TypeError 的属性):

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

编辑:

将以下内容添加到您的代码中并运行(将 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”
  • 在现有的 rss2email 安装上尝试新的“feeds.dat”

请参阅r2e在 Ubuntu 上出现 TypeError 错误。

于 2009-03-20T01:01:15.977 回答