Given an object, this tool throws up a gtk tree widget that maps all the references found. It dynamically builds the tree, which means it can handle large amounts of data and circular references.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
class Browser:
def make_row( self, piter, name, value ):
info = repr(value)
if not hasattr(value, "__dict__"):
if len(info) > 80:
# it's a big list, or dict etc.
info = info[:80] + "..."
_piter = self.treestore.append( piter, [ name, type(value).__name__, info ] )
return _piter
def make_instance( self, value, piter ):
if hasattr( value, "__dict__" ):
for _name, _value in value.__dict__.items():
_piter = self.make_row( piter, "."+_name, _value )
_path = self.treestore.get_path( _piter )
self.otank[ _path ] = (_name, _value)
def make_mapping( self, value, piter ):
keys = []
if hasattr( value, "keys" ):
keys = value.keys()
elif hasattr( value, "__len__"):
keys = range( len(value) )
for key in keys:
_name = "[%s]"%str(key)
_piter = self.make_row( piter, _name, value[key] )
_path = self.treestore.get_path( _piter )
self.otank[ _path ] = (_name, value[key])
def make(self, name=None, value=None, path=None, depth=1):
if path is None:
# make root node
piter = self.make_row( None, name, value )
path = self.treestore.get_path( piter )
self.otank[ path ] = (name, value)
else:
name, value = self.otank[ path ]
piter = self.treestore.get_iter( path )
if not self.treestore.iter_has_child( piter ):
self.make_mapping( value, piter )
self.make_instance( value, piter )
if depth:
for i in range( self.treestore.iter_n_children( piter ) ):
self.make( path = path+(i,), depth = depth - 1 )
def row_expanded( self, treeview, piter, path ):
self.make( path = path )
def delete_event(self, widget, event, data=None):
gtk.main_quit()
return gtk.FALSE
def __init__(self, name, value):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title("Browser")
self.window.set_size_request(512, 320)
self.window.connect("delete_event", self.delete_event)
# we will store the name, the type name, and the repr
columns = [str,str,str]
self.treestore = gtk.TreeStore(*columns)
# the otank tells us what object we put at each node in the tree
self.otank = {} # map path -> (name,value)
self.make( name, value )
self.treeview = gtk.TreeView(self.treestore)
self.treeview.connect("row-expanded", self.row_expanded )
self.tvcolumns = [ gtk.TreeViewColumn() for _type in columns ]
i = 0
for tvcolumn in self.tvcolumns:
self.treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', i)
i = i + 1
self.window.add(self.treeview)
self.window.show_all()
def dump( name, value ):
browser = Browser( name, value )
gtk.main()
def test():
class Nil:
pass
a = Nil()
b = Nil()
c = Nil()
d = Nil()
a.b=b
b.c=c
c.d=d
d.a=a # circular chain
dump( "a", a )
if __name__ == "__main__":
test()
|
This script is useful for debugging the suspect object that has just caused an exception by calling the dump( ) routine from the except clause of your script. It is also good for checking through old pickled data, or other complex object stores.
The make* routines can be adjusted to taste: for example to search through dir(value) to obtain information about modules and classes.
This is inspired by a browse.py script supplied with the pygtk distribution, that alas, has not been updated to pygtk-2.x. See also the TreeView example in the excellent pygtk tutorial by John Finlay.
This code is useful but is broken when an object contains Python 'sets', eg
x = set([3,4,5])
Sets are different because they have a __len__ attribute, but are not indexable.
It seems likely that this highlights a more general failing of the code. If I manage to work out a better implementation, I'll post it here.
See here: http://ascendcode.cheme.cmu.edu/viewvc.cgi/code/branches/extfn/pygtk/canvas/obrowser.py