ZODB: How to get and read objects from an undo information

This is useful for example if you have transactions that cause writes to the database and you don't know what has been written. First, identify the ID of the transaction that you're interested. In the Undo tab of Zope, inspect the checkbox for the transaction and copy the part that looks like an id from its value.

Then, in a zope debugging shell (started with bin/instance debug), I've done:

>>> import base64, cPickle
>>> webtid = "QTY1MjhoaytpMVU9"

# DB will be the "database", as represented in Zope.
>>> db = app._p_jar.db()

# Storage will be an instance of FileStorage. I don't think 
# it's possible to achieve this connected through ZEO.
>>> storage = db.storage

# This is the "real" transaction id
>>> tid = base64.decodestring(webtid + "\n")

# Now we'll get a "transaction position", a position 
# in the filestorage where the transaction begins
>>> tpos = storage._txn_find(tid, True)

# This will be the transaction header. This is the info that's 
# shown in the Undo UI.
>>> th = storage._read_txn_header(tpos)
>>> print th.status, th.descr, th.user

# Now we get the "data position", the position in the zodb where 
# the objects of that transaction sit
>>> pos = tpos + th.headerlen()

# This will be the data header
>>> dh = storage._read_data_header(pos)

# we're very much interested in the oid
>>> oid = dh.oid
>>> pickle_data, tid = storage.load(oid)

# heh, zodb is just a pickle store, you knew that, right?
>>> print pickle_data
>>> print cPickle.loads(pickle_data)

# but it's easier to get the object using the zope machinery
>>> obj = app._p_jar[oid] 
>>> print obj

The zope process needs to be configured with a FileStorage, not a ClientStorage (aka Zeo client).